Added and used new utility type functions for bit-fields.

Fixed GetUnderlyingTypeCode() for bit-fields with widths > 16.
This commit is contained in:
acqn
2021-12-01 09:45:17 +08:00
committed by mrdudz
parent be5298925c
commit ff1eca5701
6 changed files with 95 additions and 56 deletions

View File

@@ -156,19 +156,8 @@ void DoIncDecBitField (ExprDesc* Expr, long Val, unsigned KeepResult)
unsigned ChunkFlags; unsigned ChunkFlags;
const Type* ChunkType; const Type* ChunkType;
/* If the bit-field fits within one byte, do the following operations /* Determine the type to operate on the whole byte chunk containing the bit-field */
** with bytes. ChunkType = GetBitFieldChunkType (Expr->Type);
*/
if ((Expr->Type->A.B.Width - 1U) / CHAR_BITS ==
(Expr->Type->A.B.Offs + Expr->Type->A.B.Width - 1U) / CHAR_BITS) {
ChunkType = GetUnderlyingType (Expr->Type);
} else {
/* We use the declarartion integer type as the chunk type.
** Note: A bit-field will not occupy bits located in bytes more than
** that of its declaration type in cc65. So this is OK.
*/
ChunkType = Expr->Type + 1;
}
/* Determine code generator flags */ /* Determine code generator flags */
Flags = TypeOf (Expr->Type) | CF_FORCECHAR; Flags = TypeOf (Expr->Type) | CF_FORCECHAR;
@@ -254,19 +243,8 @@ static void OpAssignBitField (const GenDesc* Gen, ExprDesc* Expr, const char* Op
ED_Init (&Expr2); ED_Init (&Expr2);
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR; Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
/* If the bit-field fits within one byte, do the following operations /* Determine the type to operate on the whole byte chunk containing the bit-field */
** with bytes. ChunkType = GetBitFieldChunkType (Expr->Type);
*/
if ((Expr->Type->A.B.Width - 1U) / CHAR_BITS ==
(Expr->Type->A.B.Offs + Expr->Type->A.B.Width - 1U) / CHAR_BITS) {
ChunkType = GetUnderlyingType (Expr->Type);
} else {
/* We use the declarartion integer type as the chunk type.
** Note: A bit-field will not occupy bits located in bytes more than
** that of its declaration type in cc65. So this is OK.
*/
ChunkType = Expr->Type + 1;
}
/* Determine code generator flags */ /* Determine code generator flags */
Flags = TypeOf (Expr->Type) | CF_FORCECHAR; Flags = TypeOf (Expr->Type) | CF_FORCECHAR;
@@ -620,8 +598,8 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
if (IsClassStruct (ltype)) { if (IsClassStruct (ltype)) {
/* Copy the struct or union by value */ /* Copy the struct or union by value */
CopyStruct (Expr, &Expr2); CopyStruct (Expr, &Expr2);
} else if (IsTypeBitField (ltype)) { } else if (IsTypeFragBitField (ltype)) {
/* Special care is needed for bit-field 'op=' */ /* Special care is needed for bit-fields if they don't fit in full bytes */
OpAssignBitField (Gen, Expr, Op); OpAssignBitField (Gen, Expr, Op);
} else { } else {
/* Normal straight 'op=' */ /* Normal straight 'op=' */

View File

@@ -551,6 +551,24 @@ unsigned long GetIntegerTypeMax (const Type* Type)
static unsigned GetBitFieldMinimalTypeSize (unsigned BitWidth)
/* Return the size of the smallest integer type that may have BitWidth bits */
{
/* Since all integer types supported in cc65 for bit-fields have sizes that
** are powers of 2, we can just use this bit-twiddling trick.
*/
unsigned V = (int)(BitWidth - 1U) / (int)CHAR_BITS;
V |= V >> 1;
V |= V >> 2;
V |= V >> 4;
V |= V >> 8;
V |= V >> 16;
/* Return the result size */
return V + 1U;
}
static unsigned TypeOfBySize (unsigned Size) static unsigned TypeOfBySize (unsigned Size)
/* Get the code generator replacement type of the object by its size */ /* Get the code generator replacement type of the object by its size */
{ {
@@ -591,8 +609,7 @@ const Type* GetUnderlyingType (const Type* Type)
** bit-field, instead of the type used in the declaration, the truly ** bit-field, instead of the type used in the declaration, the truly
** underlying of the bit-field. ** underlying of the bit-field.
*/ */
unsigned Size = (int)(Type->A.B.Width - 1) / (int)CHAR_BITS + 1; switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) {
switch (Size) {
case SIZEOF_CHAR: Type = IsSignSigned (Type) ? type_schar : type_uchar; break; case SIZEOF_CHAR: Type = IsSignSigned (Type) ? type_schar : type_uchar; break;
case SIZEOF_INT: Type = IsSignSigned (Type) ? type_int : type_uint; break; case SIZEOF_INT: Type = IsSignSigned (Type) ? type_int : type_uint; break;
case SIZEOF_LONG: Type = IsSignSigned (Type) ? type_long : type_ulong; break; case SIZEOF_LONG: Type = IsSignSigned (Type) ? type_long : type_ulong; break;
@@ -646,8 +663,7 @@ TypeCode GetUnderlyingTypeCode (const Type* Type)
** bit-field, instead of the type used in the declaration, the truly ** bit-field, instead of the type used in the declaration, the truly
** underlying of the bit-field. ** underlying of the bit-field.
*/ */
unsigned Size = (int)(Type->A.B.Width - 1) / (int)CHAR_BITS + 1; switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) {
switch (Size) {
case SIZEOF_CHAR: Underlying = T_CHAR; break; case SIZEOF_CHAR: Underlying = T_CHAR; break;
case SIZEOF_INT: Underlying = T_INT; break; case SIZEOF_INT: Underlying = T_INT; break;
case SIZEOF_LONG: Underlying = T_LONG; break; case SIZEOF_LONG: Underlying = T_LONG; break;
@@ -663,6 +679,39 @@ TypeCode GetUnderlyingTypeCode (const Type* Type)
const Type* GetBitFieldChunkType (const Type* Type)
/* Get the type needed to operate on the byte chunk containing the bit-field */
{
unsigned ChunkSize;
if ((Type->A.B.Width - 1U) / CHAR_BITS ==
(Type->A.B.Offs + Type->A.B.Width - 1U) / CHAR_BITS) {
/* T bit-field fits within its underlying type */
return GetUnderlyingType (Type);
}
ChunkSize = GetBitFieldMinimalTypeSize (Type->A.B.Offs + Type->A.B.Width);
if (ChunkSize < SizeOf (Type + 1)) {
/* The end of the bit-field is offset by some bits so that it requires
** more bytes to be accessed as a whole than its underlying type does.
** Note: In cc65 the bit offset is always less than CHAR_BITS.
*/
switch (ChunkSize) {
case SIZEOF_CHAR: return IsSignSigned (Type) ? type_schar : type_uchar;
case SIZEOF_INT: return IsSignSigned (Type) ? type_int : type_uint;
case SIZEOF_LONG: return IsSignSigned (Type) ? type_long : type_ulong;
default: return IsSignSigned (Type) ? type_int : type_uint;
}
}
/* We can always use the declarartion integer type as the chunk type.
** Note: A bit-field will not occupy bits located in bytes more than that
** of its declaration type in cc65. So this is OK.
*/
return Type + 1;
}
unsigned SizeOf (const Type* T) unsigned SizeOf (const Type* T)
/* Compute size of object represented by type array. */ /* Compute size of object represented by type array. */
{ {
@@ -1127,6 +1176,15 @@ Type* NewBitFieldType (const Type* T, unsigned BitOffs, unsigned BitWidth)
int IsTypeFragBitField (const Type* T)
/* Return true if this is a bit-field that shares byte space with other fields */
{
return IsTypeBitField (T) &&
(T->A.B.Offs != 0 || T->A.B.Width != CHAR_BITS * SizeOf (T));
}
int IsClassObject (const Type* T) int IsClassObject (const Type* T)
/* Return true if this is a fully described object type */ /* Return true if this is a fully described object type */
{ {

View File

@@ -313,6 +313,9 @@ TypeCode GetUnderlyingTypeCode (const Type* Type);
** Return TCode if it is not scalar. ** Return TCode if it is not scalar.
*/ */
const Type* GetBitFieldChunkType (const Type* Type);
/* Get the type needed to operate on the byte chunk containing the bit-field */
unsigned SizeOf (const Type* T); unsigned SizeOf (const Type* T);
/* Compute size of object represented by type array. */ /* Compute size of object represented by type array. */
@@ -556,6 +559,9 @@ INLINE int IsTypeBitField (const Type* T)
# define IsTypeBitField(T) (IsTypeSignedBitField (T) || IsTypeUnsignedBitField (T)) # define IsTypeBitField(T) (IsTypeSignedBitField (T) || IsTypeUnsignedBitField (T))
#endif #endif
int IsTypeFragBitField (const Type* T);
/* Return true if this is a bit-field that shares byte space with other fields */
#if defined(HAVE_INLINE) #if defined(HAVE_INLINE)
INLINE int IsTypeStruct (const Type* T) INLINE int IsTypeStruct (const Type* T)
/* Return true if this is a struct type */ /* Return true if this is a struct type */

View File

@@ -398,7 +398,7 @@ static void DoInc (ExprDesc* Expr, unsigned KeepResult)
Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1; Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1;
/* Special treatment is needed for bit-fields */ /* Special treatment is needed for bit-fields */
if (IsTypeBitField (Expr->Type)) { if (IsTypeFragBitField (Expr->Type)) {
DoIncDecBitField (Expr, Val, KeepResult); DoIncDecBitField (Expr, Val, KeepResult);
return; return;
} }
@@ -485,7 +485,7 @@ static void DoDec (ExprDesc* Expr, unsigned KeepResult)
Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1; Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1;
/* Special treatment is needed for bit-fields */ /* Special treatment is needed for bit-fields */
if (IsTypeBitField (Expr->Type)) { if (IsTypeFragBitField (Expr->Type)) {
DoIncDecBitField (Expr, -Val, KeepResult); DoIncDecBitField (Expr, -Val, KeepResult);
return; return;
} }

View File

@@ -110,6 +110,8 @@ static void LoadAddress (unsigned Flags, ExprDesc* Expr)
void LoadExpr (unsigned Flags, struct ExprDesc* Expr) void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
/* Load an expression into the primary register if it is not already there. /* Load an expression into the primary register if it is not already there.
** If Flags contains any CF_TYPEMASK bits, it then overrides the codegen type
** info that would be otherwise taken from the expression type.
** Note: This function can't modify the content in Expr since there are many ** Note: This function can't modify the content in Expr since there are many
** instances of the "GetCodePos + LoadExpr (maybe indirectly) + RemoveCode" ** instances of the "GetCodePos + LoadExpr (maybe indirectly) + RemoveCode"
** code pattern here and there which assumes that Expr should be unchanged, ** code pattern here and there which assumes that Expr should be unchanged,
@@ -125,32 +127,24 @@ void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
int AdjustBitField = 0; int AdjustBitField = 0;
unsigned BitFieldFullWidthFlags = 0; unsigned BitFieldFullWidthFlags = 0;
if ((Flags & CF_TYPEMASK) == 0) { if ((Flags & CF_TYPEMASK) == 0) {
if (IsTypeBitField (Expr->Type)) { if (IsTypeFragBitField (Expr->Type)) {
unsigned EndBit = Expr->Type->A.B.Offs + Expr->Type->A.B.Width; /* We need to adjust the bits in this case. */
AdjustBitField = Expr->Type->A.B.Offs != 0 || (EndBit != CHAR_BITS && EndBit != INT_BITS); AdjustBitField = 1;
/* TODO: This probably needs to be guarded by AdjustBitField when long bit-fields are
** supported.
*/
Flags |= (EndBit <= CHAR_BITS) ? CF_CHAR : CF_INT;
if (IsSignUnsigned (Expr->Type)) {
Flags |= CF_UNSIGNED;
}
/* Flags we need operate on the whole bit-field, without CF_FORCECHAR. */ /* Flags we need operate on the whole bit-field, without CF_FORCECHAR. */
BitFieldFullWidthFlags = Flags; BitFieldFullWidthFlags = Flags | TypeOf (Expr->Type);
/* Flags we need operate on the whole chunk containing the bit-field. */
Flags |= TypeOf (GetBitFieldChunkType (Expr->Type));
/* If we're adjusting, then only load a char (not an int) and do only char ops; /* If we're adjusting, then only load a char (not an int) and do only char ops;
** We will clear the high byte in the adjustment. CF_FORCECHAR does nothing if the ** We will clear the high byte in the adjustment. CF_FORCECHAR does nothing if
** type is not CF_CHAR. ** the type is not CF_CHAR;
*/ ** If adjusting, then we're sign extending manually, so do everything unsigned
if (AdjustBitField) {
/* If adjusting, then we're sign extending manually, so do everything unsigned
** to make shifts faster. ** to make shifts faster.
*/ */
Flags |= CF_UNSIGNED | CF_FORCECHAR; Flags |= CF_UNSIGNED | CF_FORCECHAR;
BitFieldFullWidthFlags |= CF_UNSIGNED; BitFieldFullWidthFlags |= CF_UNSIGNED;
}
} else { } else {
/* If Expr is an incomplete ESY type, bail out */ /* If Expr is an incomplete ESY type, bail out */
if (IsIncompleteESUType (Expr->Type)) { if (IsIncompleteESUType (Expr->Type)) {

View File

@@ -55,7 +55,10 @@ struct ExprDesc;
void LoadExpr (unsigned Flags, struct ExprDesc* Expr); void LoadExpr (unsigned Flags, struct ExprDesc* Expr);
/* Load an expression into the primary register if it is not already there. */ /* Load an expression into the primary register if it is not already there.
** If Flags contains any CF_TYPEMASK bits, it then overrides the codegen type
** info that would be otherwise taken from the expression type.
*/