mirror of
https://github.com/cc65/cc65.git
synced 2025-02-04 13:32:54 +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:
parent
a47008cca0
commit
10c949062b
@ -381,7 +381,7 @@ INLINE int IsTypeArray (const Type* T)
|
|||||||
/* Return true if this is an array type */
|
/* Return true if this is an array type */
|
||||||
{
|
{
|
||||||
return (GetType (T) == T_TYPE_ARRAY);
|
return (GetType (T) == T_TYPE_ARRAY);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define IsTypeArray(T) (GetType (T) == T_TYPE_ARRAY)
|
# define IsTypeArray(T) (GetType (T) == T_TYPE_ARRAY)
|
||||||
#endif
|
#endif
|
||||||
@ -496,8 +496,18 @@ INLINE int IsSignUnsigned (const Type* T)
|
|||||||
# define IsSignUnsigned(T) (GetSignedness (T) == T_SIGN_UNSIGNED)
|
# define IsSignUnsigned(T) (GetSignedness (T) == T_SIGN_UNSIGNED)
|
||||||
#endif
|
#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));
|
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)
|
#if defined(HAVE_INLINE)
|
||||||
INLINE int IsQualConst (const Type* T)
|
INLINE int IsQualConst (const Type* T)
|
||||||
|
172
src/cc65/expr.c
172
src/cc65/expr.c
@ -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)
|
static const GenDesc* FindGen (token_t Tok, const GenDesc* Table)
|
||||||
/* Find a token in a generator 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 */
|
/* Both operands are constant, remove the generated code */
|
||||||
RemoveCode (&Mark1);
|
RemoveCode (&Mark1);
|
||||||
|
|
||||||
/* Evaluate the result */
|
|
||||||
Expr->IVal = kcalc (Tok, Expr->IVal, Expr2.IVal);
|
|
||||||
|
|
||||||
/* Get the type of the result */
|
/* Get the type of the result */
|
||||||
Expr->Type = promoteint (Expr->Type, Expr2.Type);
|
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 {
|
} else {
|
||||||
|
|
||||||
/* If the right hand side is constant, and the generator function
|
/* 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 Mark1;
|
||||||
CodeMark Mark2;
|
CodeMark Mark2;
|
||||||
const GenDesc* Gen;
|
const GenDesc* Gen;
|
||||||
token_t tok; /* The operator token */
|
token_t Tok; /* The operator token */
|
||||||
unsigned ltype;
|
unsigned ltype;
|
||||||
int rconst; /* Operand is a constant */
|
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) {
|
while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
|
||||||
|
|
||||||
/* Remember the operator token, then skip it */
|
/* Remember the operator token, then skip it */
|
||||||
tok = CurTok.Tok;
|
Tok = CurTok.Tok;
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
/* Get the lhs on stack */
|
/* Get the lhs on stack */
|
||||||
@ -1759,21 +1789,51 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */
|
|||||||
Type* right = Indirect (Expr2.Type);
|
Type* right = Indirect (Expr2.Type);
|
||||||
if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
|
if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
|
||||||
/* Incomatible pointers */
|
/* Incomatible pointers */
|
||||||
Error ("Incompatible types");
|
Error ("Incompatible types");
|
||||||
}
|
}
|
||||||
} else if (!ED_IsNullPtr (&Expr2)) {
|
} else if (!ED_IsNullPtr (&Expr2)) {
|
||||||
Error ("Incompatible types");
|
Error ("Incompatible types");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for const operands */
|
/* Check for const operands */
|
||||||
if (ED_IsConstAbs (Expr) && rconst) {
|
if (ED_IsConstAbs (Expr) && rconst) {
|
||||||
|
|
||||||
/* Both operands are constant, remove the generated code */
|
/* Both operands are constant, remove the generated code */
|
||||||
RemoveCode (&Mark1);
|
RemoveCode (&Mark1);
|
||||||
|
|
||||||
/* Evaluate the result */
|
/* Determine if this is a signed or unsigned compare */
|
||||||
Expr->IVal = kcalc (tok, Expr->IVal, Expr2.IVal);
|
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 {
|
} else {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user