1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-01 13:41:34 +00:00

Fixed a bug: The compiler evaluated constant expressions internally always

using signed integers as data types. This led to wrong results for mod, div
and compares.


git-svn-id: svn://svn.cc65.org/cc65/trunk@3797 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2007-08-26 18:53:46 +00:00
parent a47008cca0
commit 10c949062b
2 changed files with 128 additions and 58 deletions

View File

@ -381,7 +381,7 @@ INLINE int IsTypeArray (const Type* T)
/* Return true if this is an array type */
{
return (GetType (T) == T_TYPE_ARRAY);
}
}
#else
# define IsTypeArray(T) (GetType (T) == T_TYPE_ARRAY)
#endif
@ -496,8 +496,18 @@ INLINE int IsSignUnsigned (const Type* T)
# define IsSignUnsigned(T) (GetSignedness (T) == T_SIGN_UNSIGNED)
#endif
#if defined(HAVE_INLINE)
INLINE int IsSignSigned (const Type* T)
/* Return true if this is a signed type */
{
return (GetSignedness (T) == T_SIGN_SIGNED);
}
#else
# define IsSignSigned(T) (GetSignedness (T) == T_SIGN_SIGNED)
#endif
TypeCode GetQualifier (const Type* T) attribute ((const));
/* Get the qualifier from the given type string */
/* Get the qualifier from the given type string */
#if defined(HAVE_INLINE)
INLINE int IsQualConst (const Type* T)

View File

@ -181,50 +181,6 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush)
static int kcalc (token_t tok, long val1, long val2)
/* Calculate an operation with left and right operand constant. */
{
switch (tok) {
case TOK_EQ:
return (val1 == val2);
case TOK_NE:
return (val1 != val2);
case TOK_LT:
return (val1 < val2);
case TOK_LE:
return (val1 <= val2);
case TOK_GE:
return (val1 >= val2);
case TOK_GT:
return (val1 > val2);
case TOK_OR:
return (val1 | val2);
case TOK_XOR:
return (val1 ^ val2);
case TOK_AND:
return (val1 & val2);
case TOK_STAR:
return (val1 * val2);
case TOK_DIV:
if (val2 == 0) {
Error ("Division by zero");
return 0x7FFFFFFF;
}
return (val1 / val2);
case TOK_MOD:
if (val2 == 0) {
Error ("Modulo operation with zero");
return 0;
}
return (val1 % val2);
default:
Internal ("kcalc: got token 0x%X\n", tok);
return 0;
}
}
static const GenDesc* FindGen (token_t Tok, const GenDesc* Table)
/* Find a token in a generator table */
{
@ -1662,12 +1618,86 @@ static void hie_internal (const GenDesc* Ops, /* List of generators */
/* Both operands are constant, remove the generated code */
RemoveCode (&Mark1);
/* Evaluate the result */
Expr->IVal = kcalc (Tok, Expr->IVal, Expr2.IVal);
/* Get the type of the result */
Expr->Type = promoteint (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) {
Error ("Division by zero");
Expr->IVal = 0x7FFFFFFF;
} 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);
}
} 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);
}
}
} else {
/* If the right hand side is constant, and the generator function
@ -1715,7 +1745,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
CodeMark Mark1;
CodeMark Mark2;
const GenDesc* Gen;
token_t tok; /* The operator token */
token_t Tok; /* The operator token */
unsigned ltype;
int rconst; /* Operand is a constant */
@ -1725,7 +1755,7 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
/* Remember the operator token, then skip it */
tok = CurTok.Tok;
Tok = CurTok.Tok;
NextToken ();
/* Get the lhs on stack */
@ -1759,21 +1789,51 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
Type* right = Indirect (Expr2.Type);
if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
/* Incomatible pointers */
Error ("Incompatible types");
}
Error ("Incompatible types");
}
} else if (!ED_IsNullPtr (&Expr2)) {
Error ("Incompatible types");
Error ("Incompatible types");
}
}
/* Check for const operands */
if (ED_IsConstAbs (Expr) && rconst) {
/* Both operands are constant, remove the generated code */
RemoveCode (&Mark1);
/* Both operands are constant, remove the generated code */
RemoveCode (&Mark1);
/* Evaluate the result */
Expr->IVal = kcalc (tok, Expr->IVal, Expr2.IVal);
/* Determine if this is a signed or unsigned compare */
if (IsClassInt (Expr->Type) && IsSignSigned (Expr->Type) &&
IsClassInt (Expr2.Type) && IsSignSigned (Expr2.Type)) {
/* Evaluate the result for signed operands */
signed long Val1 = Expr->IVal;
signed long Val2 = Expr2.IVal;
switch (Tok) {
case TOK_EQ: Expr->IVal = (Val1 == Val2); break;
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
default: Internal ("hie_compare: 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_EQ: Expr->IVal = (Val1 == Val2); break;
case TOK_NE: Expr->IVal = (Val1 != Val2); break;
case TOK_LT: Expr->IVal = (Val1 < Val2); break;
case TOK_LE: Expr->IVal = (Val1 <= Val2); break;
case TOK_GE: Expr->IVal = (Val1 >= Val2); break;
case TOK_GT: Expr->IVal = (Val1 > Val2); break;
default: Internal ("hie_compare: got token 0x%X\n", Tok);
}
}
} else {