From 10c949062bd22ee4b06c712c069226dc95a547af Mon Sep 17 00:00:00 2001 From: cuz Date: Sun, 26 Aug 2007 18:53:46 +0000 Subject: [PATCH] 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 --- src/cc65/datatype.h | 14 +++- src/cc65/expr.c | 172 +++++++++++++++++++++++++++++--------------- 2 files changed, 128 insertions(+), 58 deletions(-) diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index ac69f0d16..c3467d0dc 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -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) diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 03fcef97b..6ddb685e5 100644 --- a/src/cc65/expr.c +++ b/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) /* 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); + + /* 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 */ - Expr->IVal = kcalc (tok, Expr->IVal, Expr2.IVal); + /* 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 { -- 2.39.5