]> git.sur5r.net Git - cc65/blobdiff - src/cc65/expr.c
Renamed the defines in symdefs.h to something more meaningful. They were named
[cc65] / src / cc65 / expr.c
index ff5cde4f0a83685f6878cdaf174a94c245977a7b..b0bc18d1481c5a4c3148c2506737e88002fc3e6c 100644 (file)
@@ -109,12 +109,13 @@ void ExprWithCheck (void (*Func) (ExprDesc*), ExprDesc* Expr)
     /* Do some checks if code generation is still constistent */
     if (StackPtr != OldSP) {
        if (Debug) {
-                   fprintf (stderr,
-                     "Code generation messed up!\n"
-                     "StackPtr is %d, should be %d",
-                     StackPtr, OldSP);
+                   Error ("Code generation messed up: "
+                   "StackPtr is %d, should be %d",
+                   StackPtr, OldSP);
        } else {
-                   Internal ("StackPtr is %d, should be %d\n", StackPtr, OldSP);
+                   Internal ("Code generation messed up: "
+                      "StackPtr is %d, should be %d",
+                      StackPtr, OldSP);
        }
     }
 }
@@ -255,6 +256,18 @@ void PushAddr (const ExprDesc* Expr)
 
 
 
+static void WarnConstCompareResult (void)
+/* If the result of a comparison is constant, this is suspicious when not in
+ * preprocessor mode.
+ */
+{
+    if (!Preprocessing) {
+        Warning ("Result of comparison is constant");
+    }
+}
+
+
+
 /*****************************************************************************/
 /*                                  code                                    */
 /*****************************************************************************/
@@ -578,7 +591,6 @@ static void Primary (ExprDesc* E)
 /* This is the lowest level of the expression parser. */
 {
     SymEntry* Sym;
-    Literal*  L;
 
     /* Initialize fields in the expression stucture */
     ED_Init (E);
@@ -749,11 +761,11 @@ static void Primary (ExprDesc* E)
         case TOK_SCONST:
         case TOK_WCSCONST:
             /* String literal */
-            L = UseLiteral (CurTok.SVal);
+            E->LVal  = UseLiteral (CurTok.SVal);
             E->Type  = GetCharArrayType (GetLiteralSize (CurTok.SVal));
             E->Flags = E_LOC_LITERAL | E_RTYPE_RVAL;
             E->IVal  = 0;
-            E->Name  = GetLiteralLabel (CurTok.SVal);                         
+            E->Name  = GetLiteralLabel (CurTok.SVal);
             NextToken ();
             break;
 
@@ -1905,18 +1917,23 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
 /* Helper function for the compare operators */
 {
     ExprDesc Expr2;
+    CodeMark Mark0;
     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 */
 
 
+    GetCodePos (&Mark0);
     hienext (Expr);
 
     while ((Gen = FindGen (CurTok.Tok, Ops)) != 0) {
 
+        /* Remember the generator function */
+        void (*GenFunc) (unsigned, unsigned long) = Gen->Func;
+
        /* Remember the operator token, then skip it */
                Tok = CurTok.Tok;
        NextToken ();
@@ -1972,9 +1989,7 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
             /* If the result is constant, this is suspicious when not in
              * preprocessor mode.
              */
-            if (!Preprocessing) {
-                Warning ("Result of comparison is constant");
-            }
+            WarnConstCompareResult ();
 
                    /* Both operands are constant, remove the generated code */
                    RemoveCode (&Mark1);
@@ -2012,7 +2027,11 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                 }
             }
 
-       } else {
+               } else {
+
+            /* Determine the signedness of the operands */
+            int LeftSigned  = IsSignSigned (Expr->Type);
+            int RightSigned = IsSignSigned (Expr2.Type);
 
            /* If the right hand side is constant, and the generator function
             * expects the lhs in the primary, remove the push of the primary
@@ -2027,27 +2046,180 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                }
            }
 
-           /* Determine the type of the operation result. If the left
-            * operand is of type char and the right is a constant, or
-            * if both operands are of type char, we will encode the
-            * operation as char operation. Otherwise the default
-            * promotions are used.
-            */
-           if (IsTypeChar (Expr->Type) && (IsTypeChar (Expr2.Type) || rconst)) {
-               flags |= CF_CHAR;
-               if (IsSignUnsigned (Expr->Type) || IsSignUnsigned (Expr2.Type)) {
-                   flags |= CF_UNSIGNED;
-               }
-               if (rconst) {
-                   flags |= CF_FORCECHAR;
-               }
+           /* Determine the type of the operation. */
+            if (IsTypeChar (Expr->Type) && rconst) {
+
+                /* Left side is unsigned char, right side is constant.
+                 * Determine the minimum and maximum values
+                 */
+                int LeftMin, LeftMax;
+                if (LeftSigned) {
+                    LeftMin = -128;
+                    LeftMax = 127;
+                } else {
+                    LeftMin = 0;
+                    LeftMax = 255;
+                }
+                /* An integer value is always represented as a signed in the
+                 * ExprDesc structure. This may lead to false results below,
+                 * if it is actually unsigned, but interpreted as signed
+                 * because of the representation. Fortunately, in this case,
+                 * the actual value doesn't matter, since it's always greater
+                 * than what can be represented in a char. So correct the
+                 * value accordingly.
+                 */
+                if (!RightSigned && Expr2.IVal < 0) {
+                    /* Correct the value so it is an unsigned. It will then
+                     * anyway match one of the cases below.
+                     */
+                    Expr2.IVal = LeftMax + 1;
+                }
+
+                /* Comparing a char against a constant may have a constant
+                 * result.
+                 */
+                switch (Tok) {
+
+                    case TOK_EQ:
+                        if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
+                            ED_MakeConstAbsInt (Expr, 0);
+                            WarnConstCompareResult ();
+                            RemoveCode (&Mark0);
+                            goto Done;
+                        }
+                        break;
+
+                    case TOK_NE:
+                        if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
+                            ED_MakeConstAbsInt (Expr, 1);
+                            WarnConstCompareResult ();
+                            RemoveCode (&Mark0);
+                            goto Done;
+                        }
+                        break;
+
+                    case TOK_LT:
+                        if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
+                            ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax);
+                            WarnConstCompareResult ();
+                            RemoveCode (&Mark0);
+                            goto Done;
+                        }
+                        break;
+
+                    case TOK_LE:
+                        if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
+                            ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax);
+                            WarnConstCompareResult ();
+                            RemoveCode (&Mark0);
+                            goto Done;
+                        }
+                        break;
+
+                    case TOK_GE:
+                        if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
+                            ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin);
+                            WarnConstCompareResult ();
+                            RemoveCode (&Mark0);
+                            goto Done;
+                        }
+                        break;
+
+                    case TOK_GT:
+                        if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
+                            ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin);
+                            WarnConstCompareResult ();
+                            RemoveCode (&Mark0);
+                            goto Done;
+                        }
+                        break;
+
+                    default:
+                        Internal ("hie_compare: got token 0x%X\n", Tok);
+                }
+
+                /* If the result is not already constant (as evaluated in the
+                 * switch above), we can execute the operation as a char op,
+                 * since the right side constant is in a valid range.
+                 */
+                flags |= (CF_CHAR | CF_FORCECHAR);
+                if (!LeftSigned) {
+                    flags |= CF_UNSIGNED;
+                }
+
+            } else if (IsTypeChar (Expr->Type) && IsTypeChar (Expr2.Type) &&
+                GetSignedness (Expr->Type) == GetSignedness (Expr2.Type)) {
+
+                /* Both are chars with the same signedness. We can encode the
+                 * operation as a char operation.
+                 */
+                flags |= CF_CHAR;
+                if (rconst) {
+                    flags |= CF_FORCECHAR;
+                }
+                if (!LeftSigned) {
+                    flags |= CF_UNSIGNED;
+                }
            } else {
-               unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST);
+               unsigned rtype = TypeOf (Expr2.Type) | (flags & CF_CONST);
                        flags |= g_typeadjust (ltype, rtype);
            }
 
+            /* If the left side is an unsigned and the right is a constant,
+             * we may be able to change the compares to something more
+             * effective.
+             */
+            if (!LeftSigned && rconst) {
+
+                switch (Tok) {
+
+                    case TOK_LT:
+                        if (Expr2.IVal == 1) {
+                            /* An unsigned compare to one means that the value
+                             * must be zero.
+                             */
+                            GenFunc = g_eq;
+                            Expr2.IVal = 0;
+                        }
+                        break;
+
+                    case TOK_LE:
+                        if (Expr2.IVal == 0) {
+                            /* An unsigned compare to zero means that the value
+                             * must be zero.
+                             */
+                            GenFunc = g_eq;
+                        }
+                        break;
+
+                    case TOK_GE:
+                        if (Expr2.IVal == 1) {
+                            /* An unsigned compare to one means that the value
+                             * must not be zero.
+                             */
+                            GenFunc = g_ne;
+                            Expr2.IVal = 0;
+                        }
+                        break;
+
+                    case TOK_GT:
+                        if (Expr2.IVal == 0) {
+                            /* An unsigned compare to zero means that the value
+                             * must not be zero.
+                             */
+                            GenFunc = g_ne;
+                        }
+                        break;
+
+                    default:
+                        break;
+
+                }
+
+            }
+
            /* Generate code */
-           Gen->Func (flags, Expr2.IVal);
+                   GenFunc (flags, Expr2.IVal);
 
             /* The result is an rvalue in the primary */
            ED_MakeRValExpr (Expr);
@@ -2056,7 +2228,7 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
        /* Result type is always int */
                Expr->Type = type_int;
 
-       /* Condition codes are set */
+Done:   /* Condition codes are set */
        ED_TestDone (Expr);
     }
 }