(simplify_relational_operation): Rewrite and simplify.
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 31 Dec 1993 11:47:13 +0000 (11:47 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 31 Dec 1993 11:47:13 +0000 (11:47 +0000)
Add case when we can simplify A-B for compare of A and B.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@6344 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cse.c

index 9ad2fa9..888ab05 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -4276,7 +4276,12 @@ cse_gen_binary (code, mode, op0, op1)
 }
 \f
 /* Like simplify_binary_operation except used for relational operators.
-   MODE is the mode of the operands, not that of the result.  */
+   MODE is the mode of the operands, not that of the result.  If MODE
+   is VOIDmode, both operands must also be VOIDmode and we compare the
+   operands in "infinite precision".
+
+   If no simplification is possible, this function returns zero.  Otherwise,
+   it returns either const_true_rtx or const0_rtx.  */
 
 rtx
 simplify_relational_operation (code, mode, op0, op1)
@@ -4284,9 +4289,8 @@ simplify_relational_operation (code, mode, op0, op1)
      enum machine_mode mode;
      rtx op0, op1;
 {
-  register HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
-  HOST_WIDE_INT val;
-  int width = GET_MODE_BITSIZE (mode);
+  int equal, op0lt, op0ltu, op1lt, op1ltu;
+  rtx tem;
 
   /* If op0 is a compare, extract the comparison arguments from it.  */
   if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
@@ -4297,151 +4301,148 @@ simplify_relational_operation (code, mode, op0, op1)
   if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
     return 0;
 
-  /* Unlike the arithmetic operations, we can do the comparison whether
-     or not WIDTH is larger than HOST_BITS_PER_WIDE_INT because the
-     CONST_INTs are to be understood as being infinite precision as
-     is the comparison.  So there is no question of overflow.  */
-
-  if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT || width == 0)
-    {
-      /* Even if we can't compute a constant result,
-        there are some cases worth simplifying.  */
-
-      /* For non-IEEE floating-point, if the two operands are equal, we know
-        the result.  */
-      if (rtx_equal_p (op0, op1)
-         && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-             || ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
-       return (code == EQ || code == GE || code == LE || code == LEU
-               || code == GEU) ? const_true_rtx : const0_rtx;
-
+  /* For integer comparisons of A and B maybe we can simplify A - B and can
+     then simplify a comparison of that with zero.  If A and B are both either
+     a register or a CONST_INT, this can't help; testing for these cases will
+     prevent infinite recursion here and speed things up.
+
+     If CODE is an unsigned comparison, we can only do this if A - B is a
+     constant integer, and then we have to compare that integer with zero as a
+     signed comparison.  Note that this will give the incorrect result from
+     comparisons that overflow.  Since these are undefined, this is probably
+     OK.  If it causes a problem, we can check for A or B being an address
+     (fp + const or SYMBOL_REF) and only do it in that case.  */
+
+  if (INTEGRAL_MODE_P (mode) && op1 != const0_rtx
+      && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == CONST_INT)
+           && (GET_CODE (op1) == REG || GET_CODE (op1) == CONST_INT))
+      && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
+      && (GET_CODE (tem) == CONST_INT
+         || (code != GTU && code != GEU &&
+             code != LTU && code != LEU)))
+    return simplify_relational_operation (signed_condition (code),
+                                         mode, tem, const0_rtx);
+
+  /* For non-IEEE floating-point, if the two operands are equal, we know the
+     result.  */
+  if (rtx_equal_p (op0, op1)
+      && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+         || ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
+    equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
+
+  /* If the operands are floating-point constants, see if we can fold
+     the result.  */
 #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
-      else if (GET_CODE (op0) == CONST_DOUBLE
-              && GET_CODE (op1) == CONST_DOUBLE
-              && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
-       {
-         REAL_VALUE_TYPE d0, d1;
-         jmp_buf handler;
-         int op0lt, op1lt, equal;
+  else if (GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
+          && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
+    {
+      REAL_VALUE_TYPE d0, d1;
+      jmp_buf handler;
+      
+      if (setjmp (handler))
+       return 0;
 
-         if (setjmp (handler))
-           return 0;
+      set_float_handler (handler);
+      REAL_VALUE_FROM_CONST_DOUBLE (d0, op0);
+      REAL_VALUE_FROM_CONST_DOUBLE (d1, op1);
+      equal = REAL_VALUES_EQUAL (d0, d1);
+      op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
+      op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
+      set_float_handler (NULL_PTR);
+    }
+#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
 
-         set_float_handler (handler);
-         REAL_VALUE_FROM_CONST_DOUBLE (d0, op0);
-         REAL_VALUE_FROM_CONST_DOUBLE (d1, op1);
-         equal = REAL_VALUES_EQUAL (d0, d1);
-         op0lt = REAL_VALUES_LESS (d0, d1);
-         op1lt = REAL_VALUES_LESS (d1, d0);
-         set_float_handler (NULL_PTR);
+  /* Otherwise, see if the operands are both integers.  */
+  else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
+          && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
+          && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
+    {
+      int width = GET_MODE_BITSIZE (mode);
+      HOST_WIDE_INT l0u, l0s, h0u, h0s, l1u, l1s, h1u, h1s;
 
-         switch (code)
-           {
-           case EQ:
-             return equal ? const_true_rtx : const0_rtx;
-           case NE:
-             return !equal ? const_true_rtx : const0_rtx;
-           case LE:
-             return equal || op0lt ? const_true_rtx : const0_rtx;
-           case LT:
-             return op0lt ? const_true_rtx : const0_rtx;
-           case GE:
-             return equal || op1lt ? const_true_rtx : const0_rtx;
-           case GT:
-             return op1lt ? const_true_rtx : const0_rtx;
-           }
+      /* Get the two words comprising each integer constant.  */
+      if (GET_CODE (op0) == CONST_DOUBLE)
+       {
+         l0u = l0s = CONST_DOUBLE_LOW (op0);
+         h0u = h0s = CONST_DOUBLE_HIGH (op0);
        }
-#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
-
-      else if (GET_MODE_CLASS (mode) == MODE_INT
-              && width > HOST_BITS_PER_WIDE_INT
-              && (GET_CODE (op0) == CONST_DOUBLE
-                  || GET_CODE (op0) == CONST_INT)
-              && (GET_CODE (op1) == CONST_DOUBLE
-                  || GET_CODE (op1) == CONST_INT))
+      else
        {
-         HOST_WIDE_INT h0, l0, h1, l1;
-         unsigned HOST_WIDE_INT uh0, ul0, uh1, ul1;
-         int op0lt, op0ltu, equal;
-
-         if (GET_CODE (op0) == CONST_DOUBLE)
-           l0 = CONST_DOUBLE_LOW (op0), h0 = CONST_DOUBLE_HIGH (op0);
-         else
-           l0 = INTVAL (op0), h0 = l0 < 0 ? -1 : 0;
+         l0u = l0s = INTVAL (op0);
+         h0u = 0, h0s = l0s < 0 ? -1 : 0;
+       }
          
-         if (GET_CODE (op1) == CONST_DOUBLE)
-           l1 = CONST_DOUBLE_LOW (op1), h1 = CONST_DOUBLE_HIGH (op1);
-         else
-           l1 = INTVAL (op1), h1 = l1 < 0 ? -1 : 0;
+      if (GET_CODE (op1) == CONST_DOUBLE)
+       {
+         l1u = l1s = CONST_DOUBLE_LOW (op1);
+         h1u = h1s = CONST_DOUBLE_HIGH (op1);
+       }
+      else
+       {
+         l1u = l1s = INTVAL (op1);
+         h1u = 0, h1s = l1s < 0 ? -1 : 0;
+       }
 
-         uh0 = h0, ul0 = l0, uh1 = h1, ul1 = l1;
+      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
+        we have to sign or zero-extend the values.  */
+      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
+       h0u = h1u = 0, h0s = l0s < 0 ? -1 : 0, h1s = l1s < 0 ? -1 : 0;
 
-         equal = (h0 == h1 && l0 == l1);
-         op0lt = (h0 < h1 || (h0 == h1 && l0 < l1));
-         op0ltu = (uh0 < uh1 || (uh0 == uh1 && ul0 < ul1));
+      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
+       {
+         l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
+         l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
 
-         switch (code)
-           {
-           case EQ:
-             return equal ? const_true_rtx : const0_rtx;
-           case NE:
-             return !equal ? const_true_rtx : const0_rtx;
-           case LE:
-             return equal || op0lt ? const_true_rtx : const0_rtx;
-           case LT:
-             return op0lt ? const_true_rtx : const0_rtx;
-           case GE:
-             return !op0lt ? const_true_rtx : const0_rtx;
-           case GT:
-             return !equal && !op0lt ? const_true_rtx : const0_rtx;
-           case LEU:
-             return equal || op0ltu ? const_true_rtx : const0_rtx;
-           case LTU:
-             return op0ltu ? const_true_rtx : const0_rtx;
-           case GEU:
-             return !op0ltu ? const_true_rtx : const0_rtx;
-           case GTU:
-             return !equal && !op0ltu ? const_true_rtx : const0_rtx;
-           }
+         if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
+           l0s |= ((HOST_WIDE_INT) (-1) << width);
+
+         if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
+           l1s |= ((HOST_WIDE_INT) (-1) << width);
        }
 
+      equal = (h0u == h1u && l0u == l1u);
+      op0lt = (h0s < h1s || (h0s == h1s && l0s < l1s));
+      op1lt = (h1s < h0s || (h1s == h0s && l1s < l0s));
+      op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
+      op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
+    }
+
+  /* Otherwise, there are some code-specific tests we can make.  */
+  else
+    {
       switch (code)
        {
        case EQ:
-         {
-#if 0
-           /* We can't make this assumption due to #pragma weak */
-           if (CONSTANT_P (op0) && op1 == const0_rtx)
-             return const0_rtx;
+         /* References to the frame plus a constant or labels cannot
+            be zero, but a SYMBOL_REF can due to #pragma weak.  */
+         if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
+              || GET_CODE (op0) == LABEL_REF)
+#if FRAME_POINTER_REGNO != ARG_POINTGER_REGNO
+             /* On some machines, the ap reg can be 0 sometimes.  */
+             && op0 != arg_pointer_rtx
 #endif
-           if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx
-               /* On some machines, the ap reg can be 0 sometimes.  */
-               && op0 != arg_pointer_rtx)
-             return const0_rtx;
-           break;
-         }
+               )
+           return const0_rtx;
+         break;
 
        case NE:
-#if 0
-         /* We can't make this assumption due to #pragma weak */
-         if (CONSTANT_P (op0) && op1 == const0_rtx)
-           return const_true_rtx;
+         if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
+              || GET_CODE (op0) == LABEL_REF)
+#if FRAME_POINTER_REGNO != ARG_POINTER_REGNO
+             && op0 != arg_pointer_rtx
 #endif
-         if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx
-             /* On some machines, the ap reg can be 0 sometimes.  */
-             && op0 != arg_pointer_rtx)
+             )
            return const_true_rtx;
          break;
 
        case GEU:
-         /* Unsigned values are never negative, but we must be sure we are
-            actually comparing a value, not a CC operand.  */
-         if (op1 == const0_rtx && INTEGRAL_MODE_P (mode))
+         /* Unsigned values are never negative.  */
+         if (op1 == const0_rtx)
            return const_true_rtx;
          break;
 
        case LTU:
-         if (op1 == const0_rtx && INTEGRAL_MODE_P (mode))
+         if (op1 == const0_rtx)
            return const0_rtx;
          break;
 
@@ -4450,8 +4451,8 @@ simplify_relational_operation (code, mode, op0, op1)
             unsigned value.  */
          if (GET_CODE (op1) == CONST_INT
              && INTVAL (op1) == GET_MODE_MASK (mode)
-             && INTEGRAL_MODE_P (mode))
-           return const_true_rtx;
+           && INTEGRAL_MODE_P (mode))
+         return const_true_rtx;
          break;
 
        case GTU:
@@ -4465,92 +4466,33 @@ simplify_relational_operation (code, mode, op0, op1)
       return 0;
     }
 
-  /* Get the integer argument values in two forms:
-     zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
-
-  arg0 = INTVAL (op0);
-  arg1 = INTVAL (op1);
-
-  if (width < HOST_BITS_PER_WIDE_INT)
-    {
-      arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
-      arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-      arg0s = arg0;
-      if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
-       arg0s |= ((HOST_WIDE_INT) (-1) << width);
-
-      arg1s = arg1;
-      if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
-       arg1s |= ((HOST_WIDE_INT) (-1) << width);
-    }
-  else
-    {
-      arg0s = arg0;
-      arg1s = arg1;
-    }
-
-  /* Compute the value of the arithmetic.  */
-
+  /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
+     as appropriate.  */
   switch (code)
     {
-    case NE:
-      val = arg0 != arg1 ? STORE_FLAG_VALUE : 0;
-      break;
-
     case EQ:
-      val = arg0 == arg1 ? STORE_FLAG_VALUE : 0;
-      break;
-
-    case LE:
-      val = arg0s <= arg1s ? STORE_FLAG_VALUE : 0;
-      break;
-
+      return equal ? const_true_rtx : const0_rtx;
+    case NE:
+      return ! equal ? const_true_rtx : const0_rtx;
     case LT:
-      val = arg0s < arg1s ? STORE_FLAG_VALUE : 0;
-      break;
-
-    case GE:
-      val = arg0s >= arg1s ? STORE_FLAG_VALUE : 0;
-      break;
-
+      return op0lt ? const_true_rtx : const0_rtx;
     case GT:
-      val = arg0s > arg1s ? STORE_FLAG_VALUE : 0;
-      break;
-
-    case LEU:
-      val = (((unsigned HOST_WIDE_INT) arg0)
-            <= ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
-      break;
-
+      return op1lt ? const_true_rtx : const0_rtx;
     case LTU:
-      val = (((unsigned HOST_WIDE_INT) arg0)
-            < ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
-      break;
-
-    case GEU:
-      val = (((unsigned HOST_WIDE_INT) arg0)
-            >= ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
-      break;
-
+      return op0ltu ? const_true_rtx : const0_rtx;
     case GTU:
-      val = (((unsigned HOST_WIDE_INT) arg0)
-            > ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
-      break;
-
-    default:
-      abort ();
+      return op1ltu ? const_true_rtx : const0_rtx;
+    case LE:
+      return equal || op0lt ? const_true_rtx : const0_rtx;
+    case GE:
+      return equal || op1lt ? const_true_rtx : const0_rtx;
+    case LEU:
+      return equal || op0ltu ? const_true_rtx : const0_rtx;
+    case GEU:
+      return equal || op1ltu ? const_true_rtx : const0_rtx;
     }
 
-  /* Clear the bits that don't belong in our mode, unless they and our sign
-     bit are all one.  So we get either a reasonable negative value or a
-     reasonable unsigned value for this mode.  */
-  if (width < HOST_BITS_PER_WIDE_INT
-      && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-         != ((HOST_WIDE_INT) (-1) << (width - 1))))
-    val &= ((HOST_WIDE_INT) 1 << width) - 1;
-  
-  return GEN_INT (val);
+  abort ();
 }
 \f
 /* Simplify CODE, an operation with result mode MODE and three operands,