]> git.sur5r.net Git - cc65/commitdiff
Fixed a bug: The compiler evaluated constant expressions internally always
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 26 Aug 2007 18:53:46 +0000 (18:53 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 26 Aug 2007 18:53:46 +0000 (18:53 +0000)
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
src/cc65/expr.c

index ac69f0d163d17fb41be22d3243bdd9ab7fb91a7e..c3467d0dc78fa00fc17e968703e9354ada033630 100644 (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)
index 03fcef97be31def3f73f428342402904c98ea8a0..6ddb685e529865636a4a5ce41eb27543f77a3854 100644 (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);
+
+            /* 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 {