]> git.sur5r.net Git - cc65/blobdiff - src/cc65/expr.c
Fixed two compiler warnings.
[cc65] / src / cc65 / expr.c
index d9f46157ca98c46e1f81eaeea8e611c3f98bccf1..0bafb8ccfdfb8cedb6f1ff4822c841c52fdcb99c 100644 (file)
@@ -261,7 +261,7 @@ static void WarnConstCompareResult (void)
  * preprocessor mode.
  */
 {
-    if (!Preprocessing) {
+    if (!Preprocessing && IS_Get (&WarnConstComparison) != 0) {
         Warning ("Result of comparison is constant");
     }
 }
@@ -1105,6 +1105,7 @@ static void StructRef (ExprDesc* Expr)
 {
     ident Ident;
     SymEntry* Field;
+    Type* FinalType;
     TypeCode Q;
 
     /* Skip the token and check for an identifier */
@@ -1139,9 +1140,6 @@ static void StructRef (ExprDesc* Expr)
         ED_MakeLValExpr (Expr);
     }
 
-    /* Set the struct field offset */
-    Expr->IVal += Field->V.Offs;
-
     /* The type is the type of the field plus any qualifiers from the struct */
     if (IsClassStruct (Expr->Type)) {
         Q = GetQualifier (Expr->Type);
@@ -1149,27 +1147,81 @@ static void StructRef (ExprDesc* Expr)
         Q = GetQualifier (Indirect (Expr->Type));
     }
     if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) {
-        Expr->Type = Field->Type;
+        FinalType = Field->Type;
     } else {
-        Expr->Type = TypeDup (Field->Type);
-        Expr->Type->C |= Q;
+        FinalType = TypeDup (Field->Type);
+        FinalType->C |= Q;
     }
 
-    /* An struct member is actually a variable. So the rules for variables
-     * with respect to the reference type apply: If it's an array, it is
-     * a rvalue, otherwise it's an lvalue. (A function would also be a rvalue,
-     * but a struct field cannot be a function).
+    /* A struct is usually an lvalue. If not, it is a struct in the primary
+     * register.
      */
-    if (IsTypeArray (Expr->Type)) {
-        ED_MakeRVal (Expr);
+    if (ED_IsRVal (Expr) && ED_IsLocExpr (Expr) && !IsTypePtr (Expr->Type)) {
+
+        unsigned Flags = 0;
+        unsigned BitOffs;
+
+        /* Get the size of the type */
+        unsigned Size = SizeOf (Expr->Type);
+
+        /* Safety check */
+        CHECK (Field->V.Offs + Size <= SIZEOF_LONG);
+
+        /* The type of the operation depends on the type of the struct */
+        switch (Size) {
+            case 1:     Flags = CF_CHAR | CF_UNSIGNED | CF_CONST;       break;
+            case 2:     Flags = CF_INT  | CF_UNSIGNED | CF_CONST;       break;
+            case 3:     /* FALLTHROUGH */
+            case 4:     Flags = CF_LONG | CF_UNSIGNED | CF_CONST;       break;
+            default:    Internal ("Invalid struct size: %u", Size);     break;
+        }
+
+        /* Generate a shift to get the field in the proper position in the
+         * primary. For bit fields, mask the value.
+         */
+        BitOffs = Field->V.Offs * CHAR_BITS;
+        if (SymIsBitField (Field)) {
+            BitOffs += Field->V.B.BitOffs;
+            g_asr (Flags, BitOffs);
+            /* Mask the value. This is unnecessary if the shift executed above
+             * moved only zeroes into the value.
+             */
+            if (BitOffs + Field->V.B.BitWidth != Size * CHAR_BITS) {
+                g_and (CF_INT | CF_UNSIGNED | CF_CONST,
+                       (0x0001U << Field->V.B.BitWidth) - 1U);
+            }
+        } else {
+            g_asr (Flags, BitOffs);
+        }
+
+        /* Use the new type */
+        Expr->Type = FinalType;
+
     } else {
-        ED_MakeLVal (Expr);
-    }
 
-    /* Make the expression a bit field if necessary */
-    if (SymIsBitField (Field)) {
-        ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth);
+        /* Set the struct field offset */
+        Expr->IVal += Field->V.Offs;
+
+        /* Use the new type */
+        Expr->Type = FinalType;
+
+        /* An struct member is actually a variable. So the rules for variables
+         * with respect to the reference type apply: If it's an array, it is
+         * a rvalue, otherwise it's an lvalue. (A function would also be a rvalue,
+         * but a struct field cannot be a function).
+         */
+        if (IsTypeArray (Expr->Type)) {
+            ED_MakeRVal (Expr);
+        } else {
+            ED_MakeLVal (Expr);
+        }
+
+        /* Make the expression a bit field if necessary */
+        if (SymIsBitField (Field)) {
+            ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth);
+        }
     }
+
 }
 
 
@@ -2029,6 +2081,10 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
 
                } 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
             * now.
@@ -2045,11 +2101,9 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
            /* Determine the type of the operation. */
             if (IsTypeChar (Expr->Type) && rconst) {
 
-                /* Left side is unsigned char, right side is constant */
-                int LeftSigned  = IsSignSigned (Expr->Type);
-                int RightSigned = IsSignSigned (Expr2.Type);
-
-                /* Determine the minimum and maximum values */
+                /* Left side is unsigned char, right side is constant.
+                 * Determine the minimum and maximum values
+                 */
                 int LeftMin, LeftMax;
                 if (LeftSigned) {
                     LeftMin = -128;
@@ -2074,7 +2128,9 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                 }
 
                 /* Comparing a char against a constant may have a constant
-                 * result.
+                 * result. Please note: It is not possible to remove the code
+                * for the compare alltogether, because it may have side
+                * effects.
                  */
                 switch (Tok) {
 
@@ -2082,7 +2138,6 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                         if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
                             ED_MakeConstAbsInt (Expr, 0);
                             WarnConstCompareResult ();
-                            RemoveCode (&Mark0);
                             goto Done;
                         }
                         break;
@@ -2091,7 +2146,6 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                         if (Expr2.IVal < LeftMin || Expr2.IVal > LeftMax) {
                             ED_MakeConstAbsInt (Expr, 1);
                             WarnConstCompareResult ();
-                            RemoveCode (&Mark0);
                             goto Done;
                         }
                         break;
@@ -2100,7 +2154,6 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                         if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
                             ED_MakeConstAbsInt (Expr, Expr2.IVal > LeftMax);
                             WarnConstCompareResult ();
-                            RemoveCode (&Mark0);
                             goto Done;
                         }
                         break;
@@ -2109,13 +2162,7 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                         if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
                             ED_MakeConstAbsInt (Expr, Expr2.IVal >= LeftMax);
                             WarnConstCompareResult ();
-                            RemoveCode (&Mark0);
                             goto Done;
-                        } else if (!LeftSigned && Expr2.IVal == 0) {
-                            /* We can replace this by a compare to zero, because
-                             * the value of lhs may never be negative.
-                             */
-                            GenFunc = g_eq;
                         }
                         break;
 
@@ -2123,7 +2170,6 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                         if (Expr2.IVal <= LeftMin || Expr2.IVal > LeftMax) {
                             ED_MakeConstAbsInt (Expr, Expr2.IVal <= LeftMin);
                             WarnConstCompareResult ();
-                            RemoveCode (&Mark0);
                             goto Done;
                         }
                         break;
@@ -2132,13 +2178,7 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                         if (Expr2.IVal < LeftMin || Expr2.IVal >= LeftMax) {
                             ED_MakeConstAbsInt (Expr, Expr2.IVal < LeftMin);
                             WarnConstCompareResult ();
-                            RemoveCode (&Mark0);
                             goto Done;
-                        } else if (!LeftSigned && Expr2.IVal == 0) {
-                            /* We can replace this by a compare to zero, because
-                             * the value of lhs may never be negative.
-                             */
-                            GenFunc = g_ne;
                         }
                         break;
 
@@ -2165,7 +2205,7 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                 if (rconst) {
                     flags |= CF_FORCECHAR;
                 }
-                if (IsSignUnsigned (Expr->Type)) {
+                if (!LeftSigned) {
                     flags |= CF_UNSIGNED;
                 }
            } else {
@@ -2173,6 +2213,59 @@ static void hie_compare (const GenDesc* Ops,    /* List of generators */
                        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 */
                    GenFunc (flags, Expr2.IVal);