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
parent e9fec5e3fe
commit 2d96f79bc7
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;
const Type* ChunkType;
/* If the bit-field fits within one byte, do the following operations
** with bytes.
*/
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 the type to operate on the whole byte chunk containing the bit-field */
ChunkType = GetBitFieldChunkType (Expr->Type);
/* Determine code generator flags */
Flags = TypeOf (Expr->Type) | CF_FORCECHAR;
@ -254,19 +243,8 @@ static void OpAssignBitField (const GenDesc* Gen, ExprDesc* Expr, const char* Op
ED_Init (&Expr2);
Expr2.Flags |= Expr->Flags & E_MASK_KEEP_SUBEXPR;
/* If the bit-field fits within one byte, do the following operations
** with bytes.
*/
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 the type to operate on the whole byte chunk containing the bit-field */
ChunkType = GetBitFieldChunkType (Expr->Type);
/* Determine code generator flags */
Flags = TypeOf (Expr->Type) | CF_FORCECHAR;
@ -620,8 +598,8 @@ void OpAssign (const GenDesc* Gen, ExprDesc* Expr, const char* Op)
if (IsClassStruct (ltype)) {
/* Copy the struct or union by value */
CopyStruct (Expr, &Expr2);
} else if (IsTypeBitField (ltype)) {
/* Special care is needed for bit-field 'op=' */
} else if (IsTypeFragBitField (ltype)) {
/* Special care is needed for bit-fields if they don't fit in full bytes */
OpAssignBitField (Gen, Expr, Op);
} else {
/* 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)
/* 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
** underlying of the bit-field.
*/
unsigned Size = (int)(Type->A.B.Width - 1) / (int)CHAR_BITS + 1;
switch (Size) {
switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) {
case SIZEOF_CHAR: Type = IsSignSigned (Type) ? type_schar : type_uchar; break;
case SIZEOF_INT: Type = IsSignSigned (Type) ? type_int : type_uint; 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
** underlying of the bit-field.
*/
unsigned Size = (int)(Type->A.B.Width - 1) / (int)CHAR_BITS + 1;
switch (Size) {
switch (GetBitFieldMinimalTypeSize (Type->A.B.Width)) {
case SIZEOF_CHAR: Underlying = T_CHAR; break;
case SIZEOF_INT: Underlying = T_INT; 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)
/* 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)
/* 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.
*/
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);
/* 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))
#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)
INLINE int IsTypeStruct (const Type* T)
/* 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;
/* Special treatment is needed for bit-fields */
if (IsTypeBitField (Expr->Type)) {
if (IsTypeFragBitField (Expr->Type)) {
DoIncDecBitField (Expr, Val, KeepResult);
return;
}
@ -485,7 +485,7 @@ static void DoDec (ExprDesc* Expr, unsigned KeepResult)
Val = IsTypePtr (Expr->Type) ? CheckedSizeOf (Expr->Type + 1) : 1;
/* Special treatment is needed for bit-fields */
if (IsTypeBitField (Expr->Type)) {
if (IsTypeFragBitField (Expr->Type)) {
DoIncDecBitField (Expr, -Val, KeepResult);
return;
}

View File

@ -110,6 +110,8 @@ static void LoadAddress (unsigned Flags, ExprDesc* Expr)
void LoadExpr (unsigned Flags, struct ExprDesc* Expr)
/* 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
** instances of the "GetCodePos + LoadExpr (maybe indirectly) + RemoveCode"
** 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;
unsigned BitFieldFullWidthFlags = 0;
if ((Flags & CF_TYPEMASK) == 0) {
if (IsTypeBitField (Expr->Type)) {
unsigned EndBit = Expr->Type->A.B.Offs + Expr->Type->A.B.Width;
AdjustBitField = Expr->Type->A.B.Offs != 0 || (EndBit != CHAR_BITS && EndBit != INT_BITS);
/* 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;
}
if (IsTypeFragBitField (Expr->Type)) {
/* We need to adjust the bits in this case. */
AdjustBitField = 1;
/* 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;
** We will clear the high byte in the adjustment. CF_FORCECHAR does nothing if the
** type is not CF_CHAR.
** We will clear the high byte in the adjustment. CF_FORCECHAR does nothing if
** the type is not CF_CHAR;
** If adjusting, then we're sign extending manually, so do everything unsigned
** to make shifts faster.
*/
if (AdjustBitField) {
/* If adjusting, then we're sign extending manually, so do everything unsigned
** to make shifts faster.
*/
Flags |= CF_UNSIGNED | CF_FORCECHAR;
BitFieldFullWidthFlags |= CF_UNSIGNED;
}
Flags |= CF_UNSIGNED | CF_FORCECHAR;
BitFieldFullWidthFlags |= CF_UNSIGNED;
} else {
/* If Expr is an incomplete ESY type, bail out */
if (IsIncompleteESUType (Expr->Type)) {

View File

@ -55,7 +55,10 @@ struct ExprDesc;
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.
*/