mirror of
https://github.com/cc65/cc65.git
synced 2024-12-28 06:30:16 +00:00
Added utility functions to acquire bit width of types.
This commit is contained in:
parent
d0c9b2de99
commit
75be73cc8d
@ -315,19 +315,37 @@ static void OpAssignBitField (const GenDesc* Gen, ExprDesc* Expr, const char* Op
|
||||
} else if (Gen->Func == g_sub) {
|
||||
g_dec (Flags | CF_CONST, Expr2.IVal);
|
||||
} else {
|
||||
if (Expr2.IVal == 0) {
|
||||
/* Check for div by zero/mod by zero */
|
||||
if (Gen->Func == g_div) {
|
||||
Error ("Division by zero");
|
||||
} else if (Gen->Func == g_mod) {
|
||||
Error ("Modulo operation with zero");
|
||||
}
|
||||
} else if (Gen->Func == g_asl || Gen->Func == g_asr) {
|
||||
if (Expr2.IVal < 0) {
|
||||
Warning ("Shift count '%ld' is negative", Expr2.IVal);
|
||||
} else if (Expr2.IVal >= (long)(SizeOf (Expr->Type) * 8)) {
|
||||
Warning ("Shift count '%ld' >= width of type", Expr2.IVal);
|
||||
}
|
||||
if (!ED_IsUneval (Expr)) {
|
||||
if (Expr2.IVal == 0) {
|
||||
/* Check for div by zero/mod by zero */
|
||||
if (Gen->Func == g_div) {
|
||||
Error ("Division by zero");
|
||||
} else if (Gen->Func == g_mod) {
|
||||
Error ("Modulo operation with zero");
|
||||
}
|
||||
} else if (Gen->Func == g_asl || Gen->Func == g_asr) {
|
||||
const Type* CalType = IntPromotion (Expr->Type);
|
||||
unsigned ExprBits = BitSizeOf (CalType);
|
||||
|
||||
/* If the shift count is greater than or equal to the width of the
|
||||
** promoted left operand, the behaviour is undefined according to
|
||||
** the standard.
|
||||
*/
|
||||
if (Expr2.IVal < 0) {
|
||||
Warning ("Negative shift count %ld treated as %u for %s",
|
||||
Expr2.IVal,
|
||||
(unsigned)Expr2.IVal & (ExprBits - 1),
|
||||
GetBasicTypeName (CalType));
|
||||
} else if (Expr2.IVal >= (long)ExprBits) {
|
||||
Warning ("Shift count %ld >= width of %s treated as %u",
|
||||
Expr2.IVal,
|
||||
GetBasicTypeName (CalType),
|
||||
(unsigned)Expr2.IVal & (ExprBits - 1));
|
||||
}
|
||||
|
||||
/* Here we simply "wrap" the shift count around the width */
|
||||
Expr2.IVal &= ExprBits - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust the types of the operands if needed */
|
||||
@ -501,18 +519,36 @@ static void OpAssignArithmetic (const GenDesc* Gen, ExprDesc* Expr, const char*
|
||||
} else if (Gen->Func == g_sub) {
|
||||
g_dec (Flags | CF_CONST, Expr2.IVal);
|
||||
} else {
|
||||
if (Expr2.IVal == 0) {
|
||||
/* Check for div by zero/mod by zero */
|
||||
if (Gen->Func == g_div) {
|
||||
Error ("Division by zero");
|
||||
} else if (Gen->Func == g_mod) {
|
||||
Error ("Modulo operation with zero");
|
||||
}
|
||||
} else if (Gen->Func == g_asl || Gen->Func == g_asr) {
|
||||
if (Expr2.IVal < 0) {
|
||||
Warning ("Shift count '%ld' is negative", Expr2.IVal);
|
||||
} else if (Expr2.IVal >= (long)(SizeOf (Expr->Type) * 8)) {
|
||||
Warning ("Shift count '%ld' >= width of type", Expr2.IVal);
|
||||
if (!ED_IsUneval (Expr)) {
|
||||
if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) {
|
||||
/* Check for div by zero/mod by zero */
|
||||
if (Gen->Func == g_div) {
|
||||
Error ("Division by zero");
|
||||
} else if (Gen->Func == g_mod) {
|
||||
Error ("Modulo operation with zero");
|
||||
}
|
||||
} else if (Gen->Func == g_asl || Gen->Func == g_asr) {
|
||||
const Type* CalType = IntPromotion (Expr->Type);
|
||||
unsigned ExprBits = BitSizeOf (CalType);
|
||||
|
||||
/* If the shift count is greater than or equal to the width of the
|
||||
** promoted left operand, the behaviour is undefined according to
|
||||
** the standard.
|
||||
*/
|
||||
if (Expr2.IVal < 0) {
|
||||
Warning ("Negative shift count %ld treated as %u for %s",
|
||||
Expr2.IVal,
|
||||
(unsigned)Expr2.IVal & (ExprBits - 1),
|
||||
GetBasicTypeName (CalType));
|
||||
} else if (Expr2.IVal >= (long)ExprBits) {
|
||||
Warning ("Shift count %ld >= width of %s treated as %u",
|
||||
Expr2.IVal,
|
||||
GetBasicTypeName (CalType),
|
||||
(unsigned)Expr2.IVal & (ExprBits - 1));
|
||||
}
|
||||
|
||||
/* Here we simply "wrap" the shift count around the width */
|
||||
Expr2.IVal &= ExprBits - 1;
|
||||
}
|
||||
}
|
||||
Gen->Func (Flags | CF_CONST, Expr2.IVal);
|
||||
|
@ -203,6 +203,14 @@ unsigned long GetIntegerTypeMax (const Type* Type)
|
||||
|
||||
|
||||
|
||||
unsigned BitSizeOf (const Type* T)
|
||||
/* Return the size (in bit-width) of a data type */
|
||||
{
|
||||
return IsTypeBitField (T) ? T->A.B.Width : CHAR_BITS * SizeOf (T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned SizeOf (const Type* T)
|
||||
/* Compute size (in bytes) of object represented by type array */
|
||||
{
|
||||
@ -288,6 +296,17 @@ unsigned PSizeOf (const Type* T)
|
||||
|
||||
|
||||
|
||||
unsigned CheckedBitSizeOf (const Type* T)
|
||||
/* Return the size (in bit-width) of a data type. If the size is zero, emit an
|
||||
** error and return some valid size instead (so the rest of the compiler
|
||||
** doesn't have to work with invalid sizes).
|
||||
*/
|
||||
{
|
||||
return IsTypeBitField (T) ? T->A.B.Width : CHAR_BITS * CheckedSizeOf (T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned CheckedSizeOf (const Type* T)
|
||||
/* Return the size (in bytes) of a data type. If the size is zero, emit an
|
||||
** error and return some valid size instead (so the rest of the compiler
|
||||
|
@ -287,12 +287,21 @@ unsigned long GetIntegerTypeMax (const Type* Type);
|
||||
** The type must have a known size.
|
||||
*/
|
||||
|
||||
unsigned BitSizeOf (const Type* T);
|
||||
/* Return the size (in bit-width) of a data type */
|
||||
|
||||
unsigned SizeOf (const Type* T);
|
||||
/* Compute size (in bytes) of object represented by type array */
|
||||
|
||||
unsigned PSizeOf (const Type* T);
|
||||
/* Compute size (in bytes) of pointee object */
|
||||
|
||||
unsigned CheckedBitSizeOf (const Type* T);
|
||||
/* Return the size (in bit-width) of a data type. If the size is zero, emit an
|
||||
** error and return some valid size instead (so the rest of the compiler
|
||||
** doesn't have to work with invalid sizes).
|
||||
*/
|
||||
|
||||
unsigned CheckedSizeOf (const Type* T);
|
||||
/* Return the size (in bytes) of a data type. If the size is zero, emit an
|
||||
** error and return some valid size instead (so the rest of the compiler
|
||||
|
117
src/cc65/expr.c
117
src/cc65/expr.c
@ -2177,6 +2177,10 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
||||
/* Check for const operands */
|
||||
if (lconst && rconst) {
|
||||
|
||||
/* Evaluate the result for operands */
|
||||
unsigned long Val1 = Expr->IVal;
|
||||
unsigned long Val2 = Expr2.IVal;
|
||||
|
||||
/* Both operands are constant, remove the generated code */
|
||||
RemoveCode (&Mark1);
|
||||
|
||||
@ -2184,80 +2188,51 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
||||
Expr->Type = ArithmeticConvert (Expr->Type, Expr2.Type);
|
||||
|
||||
/* Handle the op differently for signed and unsigned types */
|
||||
if (IsSignSigned (Expr->Type)) {
|
||||
|
||||
/* Evaluate the result for signed operands */
|
||||
signed long Val1 = Expr->IVal;
|
||||
signed long Val2 = Expr2.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_STAR:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_STAR:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
if (!ED_IsUneval (Expr)) {
|
||||
Error ("Division by zero");
|
||||
Expr->IVal = 0x7FFFFFFF;
|
||||
}
|
||||
Expr->IVal = 0xFFFFFFFF;
|
||||
} else {
|
||||
/* Handle signed and unsigned operands differently */
|
||||
if (IsSignSigned (Expr->Type)) {
|
||||
Expr->IVal = ((long)Val1 / (long)Val2);
|
||||
} else {
|
||||
Expr->IVal = (Val1 / Val2);
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
if (!ED_IsUneval (Expr)) {
|
||||
Error ("Modulo operation with zero");
|
||||
Expr->IVal = 0;
|
||||
}
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
/* Handle signed and unsigned operands differently */
|
||||
if (IsSignSigned (Expr->Type)) {
|
||||
Expr->IVal = ((long)Val1 % (long)Val2);
|
||||
} else {
|
||||
Expr->IVal = (Val1 % Val2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("hie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Evaluate the result for unsigned operands */
|
||||
unsigned long Val1 = Expr->IVal;
|
||||
unsigned long Val2 = Expr2.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_STAR:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
Error ("Division by zero");
|
||||
Expr->IVal = 0xFFFFFFFF;
|
||||
} else {
|
||||
Expr->IVal = (Val1 / Val2);
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
Error ("Modulo operation with zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
Expr->IVal = (Val1 % Val2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("hie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("hie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
|
||||
/* Limit the calculated value to the range of its type */
|
||||
@ -2314,10 +2289,12 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
|
||||
/* Second value is constant - check for div */
|
||||
type |= CF_CONST;
|
||||
rtype |= CF_CONST;
|
||||
if (Tok == TOK_DIV && Expr2.IVal == 0) {
|
||||
Error ("Division by zero");
|
||||
} else if (Tok == TOK_MOD && Expr2.IVal == 0) {
|
||||
Error ("Modulo operation with zero");
|
||||
if (Expr2.IVal == 0 && !ED_IsUneval (Expr)) {
|
||||
if (Tok == TOK_DIV) {
|
||||
Error ("Division by zero");
|
||||
} else if (Tok == TOK_MOD) {
|
||||
Error ("Modulo operation with zero");
|
||||
}
|
||||
}
|
||||
if ((Gen->Flags & GEN_NOPUSH) != 0) {
|
||||
RemoveCode (&Mark2);
|
||||
|
@ -305,97 +305,60 @@ static void PPhie_internal (const token_t* Ops, /* List of generators */
|
||||
|
||||
if (PPEvaluationEnabled && !PPEvaluationFailed) {
|
||||
|
||||
/* Evaluate the result for operands */
|
||||
unsigned long Val1 = Expr->IVal;
|
||||
unsigned long Val2 = Rhs.IVal;
|
||||
|
||||
/* If either side is unsigned, the result is unsigned */
|
||||
Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED;
|
||||
|
||||
/* Handle the op differently for signed and unsigned integers */
|
||||
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
|
||||
|
||||
/* Evaluate the result for signed operands */
|
||||
signed long Val1 = Expr->IVal;
|
||||
signed long Val2 = Rhs.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_PLUS:
|
||||
Expr->IVal = (Val1 + Val2);
|
||||
break;
|
||||
case TOK_MINUS:
|
||||
Expr->IVal = (Val1 - Val2);
|
||||
break;
|
||||
case TOK_MUL:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Division by zero");
|
||||
Expr->IVal = 0;
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_PLUS:
|
||||
Expr->IVal = (Val1 + Val2);
|
||||
break;
|
||||
case TOK_MINUS:
|
||||
Expr->IVal = (Val1 - Val2);
|
||||
break;
|
||||
case TOK_MUL:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Division by zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
/* Handle signed and unsigned operands differently */
|
||||
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
|
||||
Expr->IVal = ((long)Val1 / (long)Val2);
|
||||
} else {
|
||||
Expr->IVal = (Val1 / Val2);
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Modulo operation with zero");
|
||||
Expr->IVal = 0;
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Modulo operation with zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
/* Handle signed and unsigned operands differently */
|
||||
if ((Expr->Flags & PPEXPR_UNSIGNED) == 0) {
|
||||
Expr->IVal = ((long)Val1 % (long)Val2);
|
||||
} else {
|
||||
Expr->IVal = (Val1 % Val2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("PPhie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Evaluate the result for unsigned operands */
|
||||
unsigned long Val1 = Expr->IVal;
|
||||
unsigned long Val2 = Rhs.IVal;
|
||||
switch (Tok) {
|
||||
case TOK_OR:
|
||||
Expr->IVal = (Val1 | Val2);
|
||||
break;
|
||||
case TOK_XOR:
|
||||
Expr->IVal = (Val1 ^ Val2);
|
||||
break;
|
||||
case TOK_AND:
|
||||
Expr->IVal = (Val1 & Val2);
|
||||
break;
|
||||
case TOK_PLUS:
|
||||
Expr->IVal = (Val1 + Val2);
|
||||
break;
|
||||
case TOK_MINUS:
|
||||
Expr->IVal = (Val1 - Val2);
|
||||
break;
|
||||
case TOK_MUL:
|
||||
Expr->IVal = (Val1 * Val2);
|
||||
break;
|
||||
case TOK_DIV:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Division by zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
Expr->IVal = (Val1 / Val2);
|
||||
}
|
||||
break;
|
||||
case TOK_MOD:
|
||||
if (Val2 == 0) {
|
||||
PPError ("Modulo operation with zero");
|
||||
Expr->IVal = 0;
|
||||
} else {
|
||||
Expr->IVal = (Val1 % Val2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("PPhie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Internal ("PPhie_internal: got token 0x%X\n", Tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,22 +139,27 @@ void ShiftExpr (struct ExprDesc* Expr)
|
||||
/* Remove the code that pushes the rhs onto the stack. */
|
||||
RemoveCode (&Mark2);
|
||||
|
||||
/* If the shift count is greater or equal than the bit count of
|
||||
** the operand, the behaviour is undefined according to the
|
||||
** standard.
|
||||
/* If the shift count is greater than or equal to the width of the
|
||||
** promoted left operand, the behaviour is undefined according to
|
||||
** the standard.
|
||||
*/
|
||||
if (Expr2.IVal < 0) {
|
||||
|
||||
Warning ("Shift count '%ld' is negative", Expr2.IVal);
|
||||
Expr2.IVal &= ExprBits - 1;
|
||||
|
||||
} else if (Expr2.IVal >= (long) ExprBits) {
|
||||
|
||||
Warning ("Shift count '%ld' >= width of type", Expr2.IVal);
|
||||
Expr2.IVal &= ExprBits - 1;
|
||||
|
||||
if (!ED_IsUneval (Expr)) {
|
||||
if (Expr2.IVal < 0) {
|
||||
Warning ("Negative shift count %ld treated as %u for %s",
|
||||
Expr2.IVal,
|
||||
(unsigned)Expr2.IVal & (ExprBits - 1),
|
||||
GetBasicTypeName (ResultType));
|
||||
} else if (Expr2.IVal >= (long) ExprBits) {
|
||||
Warning ("Shift count %ld >= width of %s treated as %u",
|
||||
Expr2.IVal,
|
||||
GetBasicTypeName (ResultType),
|
||||
(unsigned)Expr2.IVal & (ExprBits - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/* Here we simply "wrap" the shift count around the width */
|
||||
Expr2.IVal &= ExprBits - 1;
|
||||
|
||||
/* If the shift count is zero, nothing happens. If the left hand
|
||||
** side is a constant, the result is constant.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user