mirror of
https://github.com/cc65/cc65.git
synced 2024-12-25 02:29:52 +00:00
Added and used new utility type functions for bit-fields.
Fixed GetUnderlyingTypeCode() for bit-fields with widths > 16.
This commit is contained in:
parent
be5298925c
commit
ff1eca5701
@ -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=' */
|
||||
|
@ -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 */
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user