OSDN Git Service

* config/darwin-c.c (add_framework): Copy the directory name as it
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index 7f6b549..74377b6 100644 (file)
@@ -50,6 +50,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  ((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
 
 static rtx neg_const_int (enum machine_mode, rtx);
+static bool mode_signbit_p (enum machine_mode, rtx);
 static int simplify_plus_minus_op_data_cmp (const void *, const void *);
 static rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx,
                                rtx, int);
@@ -57,6 +58,8 @@ static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode,
                                  unsigned int);
 static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
                                           rtx, rtx);
+static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
+                                           enum machine_mode, rtx, rtx);
 \f
 /* Negate a CONST_INT rtx, truncating (because a conversion from a
    maximally negative number can overflow).  */
@@ -66,6 +69,39 @@ neg_const_int (enum machine_mode mode, rtx i)
   return gen_int_mode (- INTVAL (i), mode);
 }
 
+/* Test whether expression, X, is an immediate constant that represents
+   the most significant bit of machine mode MODE.  */
+
+static bool
+mode_signbit_p (enum machine_mode mode, rtx x)
+{
+  unsigned HOST_WIDE_INT val;
+  unsigned int width;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return false;
+
+  width = GET_MODE_BITSIZE (mode);
+  if (width == 0)
+    return false;
+  
+  if (width <= HOST_BITS_PER_WIDE_INT
+      && GET_CODE (x) == CONST_INT)
+    val = INTVAL (x);
+  else if (width <= 2 * HOST_BITS_PER_WIDE_INT
+          && GET_CODE (x) == CONST_DOUBLE
+          && CONST_DOUBLE_LOW (x) == 0)
+    {
+      val = CONST_DOUBLE_HIGH (x);
+      width -= HOST_BITS_PER_WIDE_INT;
+    }
+  else
+    return false;
+
+  if (width < HOST_BITS_PER_WIDE_INT)
+    val &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+  return val == ((unsigned HOST_WIDE_INT) 1 << (width - 1));
+}
 \f
 /* Make a binary operation by properly ordering the operands and
    seeing if the expression folds.  */
@@ -77,7 +113,7 @@ simplify_gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0,
   rtx tem;
 
   /* Put complex operands first and constants second if commutative.  */
-  if (GET_RTX_CLASS (code) == 'c'
+  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
       && swap_commutative_operands_p (op0, op1))
     tem = op0, op0 = op1, op1 = tem;
 
@@ -132,7 +168,7 @@ avoid_constant_pool_reference (rtx x)
   addr = XEXP (x, 0);
 
   /* Call target hook to avoid the effects of -fpic etc....  */
-  addr = (*targetm.delegitimize_address) (addr);
+  addr = targetm.delegitimize_address (addr);
 
   if (GET_CODE (addr) == LO_SUM)
     addr = XEXP (addr, 1);
@@ -187,10 +223,9 @@ simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
 
   return gen_rtx_fmt_eee (code, mode, op0, op1, op2);
 }
-\f
+
 /* Likewise, for relational operations.
-   CMP_MODE specifies mode comparison is done in.
-  */
+   CMP_MODE specifies mode comparison is done in.  */
 
 rtx
 simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
@@ -198,61 +233,9 @@ simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
 {
   rtx tem;
 
-  if (cmp_mode == VOIDmode)
-    cmp_mode = GET_MODE (op0);
-  if (cmp_mode == VOIDmode)
-    cmp_mode = GET_MODE (op1);
-
-  if (cmp_mode != VOIDmode)
-    {
-      tem = simplify_relational_operation (code, cmp_mode, op0, op1);
-
-      if (tem)
-       {
-#ifdef FLOAT_STORE_FLAG_VALUE
-         if (GET_MODE_CLASS (mode) == MODE_FLOAT)
-           {
-             REAL_VALUE_TYPE val;
-             if (tem == const0_rtx)
-               return CONST0_RTX (mode);
-             if (tem != const_true_rtx)
-               abort ();
-             val = FLOAT_STORE_FLAG_VALUE (mode);
-             return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
-           }
-#endif
-         return tem;
-       }
-    }
-
-  /* For the following tests, ensure const0_rtx is op1.  */
-  if (swap_commutative_operands_p (op0, op1)
-      || (op0 == const0_rtx && op1 != const0_rtx))
-    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
-
-  /* If op0 is a compare, extract the comparison arguments from it.  */
-  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
-    return simplify_gen_relational (code, mode, VOIDmode,
-                                   XEXP (op0, 0), XEXP (op0, 1));
-
-  /* If op0 is a comparison, extract the comparison arguments form it.  */
-  if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && op1 == const0_rtx)
-    {
-      if (code == NE)
-       {
-         if (GET_MODE (op0) == mode)
-           return op0;
-         return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
-                                         XEXP (op0, 0), XEXP (op0, 1));
-       }
-      else if (code == EQ)
-       {
-         enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
-         if (new != UNKNOWN)
-           return simplify_gen_relational (new, mode, VOIDmode,
-                                           XEXP (op0, 0), XEXP (op0, 1));
-        }
-    }
+  if (0 != (tem = simplify_relational_operation (code, mode, cmp_mode,
+                                                op0, op1)))
+    return tem;
 
   return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
@@ -277,7 +260,7 @@ simplify_replace_rtx (rtx x, rtx old, rtx new)
 
   switch (GET_RTX_CLASS (code))
     {
-    case '1':
+    case RTX_UNARY:
       op0 = XEXP (x, 0);
       op_mode = GET_MODE (op0);
       op0 = simplify_replace_rtx (op0, old, new);
@@ -285,15 +268,16 @@ simplify_replace_rtx (rtx x, rtx old, rtx new)
        return x;
       return simplify_gen_unary (code, mode, op0, op_mode);
 
-    case '2':
-    case 'c':
+    case RTX_BIN_ARITH:
+    case RTX_COMM_ARITH:
       op0 = simplify_replace_rtx (XEXP (x, 0), old, new);
       op1 = simplify_replace_rtx (XEXP (x, 1), old, new);
       if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
        return x;
       return simplify_gen_binary (code, mode, op0, op1);
 
-    case '<':
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
       op0 = XEXP (x, 0);
       op1 = XEXP (x, 1);
       op_mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
@@ -303,8 +287,8 @@ simplify_replace_rtx (rtx x, rtx old, rtx new)
        return x;
       return simplify_gen_relational (code, mode, op_mode, op0, op1);
 
-    case '3':
-    case 'b':
+    case RTX_TERNARY:
+    case RTX_BITFIELD_OPS:
       op0 = XEXP (x, 0);
       op_mode = GET_MODE (op0);
       op0 = simplify_replace_rtx (op0, old, new);
@@ -316,7 +300,7 @@ simplify_replace_rtx (rtx x, rtx old, rtx new)
        op_mode = GET_MODE (op0);
       return simplify_gen_ternary (code, mode, op_mode, op0, op1, op2);
 
-    case 'x':
+    case RTX_EXTRA:
       /* The only case we try to handle is a SUBREG.  */
       if (code == SUBREG)
        {
@@ -330,7 +314,7 @@ simplify_replace_rtx (rtx x, rtx old, rtx new)
        }
       break;
 
-    case 'o':
+    case RTX_OBJ:
       if (code == MEM)
        {
          op0 = simplify_replace_rtx (XEXP (x, 0), old, new);
@@ -771,7 +755,16 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
        case FIX:
          real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
          break;
+       case NOT:
+         {
+           long tmp[4];
+           int i;
 
+           real_to_target (tmp, &d, GET_MODE (trueop));
+           for (i = 0; i < 4; i++)
+             tmp[i] = ~tmp[i];
+           real_from_target (&d, tmp, mode);
+         }
        default:
          abort ();
        }
@@ -893,7 +886,7 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
            return XEXP (op, 0);
 
          /* (not (eq X Y)) == (ne X Y), etc.  */
-         if (GET_RTX_CLASS (GET_CODE (op)) == '<'
+         if (COMPARISON_P (op)
              && (mode == BImode || STORE_FLAG_VALUE == -1)
              && ((reversed = reversed_comparison_code (op, NULL_RTX))
                  != UNKNOWN))
@@ -917,6 +910,16 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
                                                   mode)) != 0)
            return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
 
+         /* (not (plus X C)) for signbit C is (xor X D) with D = ~C.  */
+         if (GET_CODE (op) == PLUS
+             && GET_CODE (XEXP (op, 1)) == CONST_INT
+             && mode_signbit_p (mode, XEXP (op, 1))
+             && (temp = simplify_unary_operation (NOT, mode,
+                                                  XEXP (op, 1),
+                                                  mode)) != 0)
+           return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
+
+
 
          /* (not (ashift 1 X)) is (rotate ~1 X).  We used to do this for
             operands other than 1, but that is not valid.  We could do a
@@ -933,7 +936,7 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
          /* If STORE_FLAG_VALUE is -1, (not (comparison X Y)) can be done
             by reversing the comparison code if valid.  */
          if (STORE_FLAG_VALUE == -1
-             && GET_RTX_CLASS (GET_CODE (op)) == '<'
+             && COMPARISON_P (op)
              && (reversed = reversed_comparison_code (op, NULL_RTX))
                 != UNKNOWN)
            return simplify_gen_relational (reversed, mode, VOIDmode,
@@ -1018,6 +1021,22 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
                                            XEXP (op, 1));
            }
 
+         /* (neg (ashiftrt X C)) can be replaced by (lshiftrt X C) when
+            C is equal to the width of MODE minus 1.  */
+         if (GET_CODE (op) == ASHIFTRT
+             && GET_CODE (XEXP (op, 1)) == CONST_INT
+             && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
+               return simplify_gen_binary (LSHIFTRT, mode,
+                                           XEXP (op, 0), XEXP (op, 1));
+
+         /* (neg (lshiftrt X C)) can be replaced by (ashiftrt X C) when
+            C is equal to the width of MODE minus 1.  */
+         if (GET_CODE (op) == LSHIFTRT
+             && GET_CODE (XEXP (op, 1)) == CONST_INT
+             && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
+               return simplify_gen_binary (ASHIFTRT, mode,
+                                           XEXP (op, 0), XEXP (op, 1));
+
          break;
 
        case SIGN_EXTEND:
@@ -1156,16 +1175,19 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
   rtx trueop0, trueop1;
   rtx tem;
 
+#ifdef ENABLE_CHECKING
   /* Relational operations don't work here.  We must know the mode
      of the operands in order to do the comparison correctly.
      Assuming a full word can give incorrect results.
      Consider comparing 128 with -128 in QImode.  */
 
-  if (GET_RTX_CLASS (code) == '<')
+  if (GET_RTX_CLASS (code) == RTX_COMPARE
+      || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
     abort ();
+#endif
 
   /* Make sure the constant is second.  */
-  if (GET_RTX_CLASS (code) == 'c'
+  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
       && swap_commutative_operands_p (op0, op1))
     {
       tem = op0, op0 = op1, op1 = tem;
@@ -1210,26 +1232,56 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
       && GET_CODE (trueop1) == CONST_DOUBLE
       && mode == GET_MODE (op0) && mode == GET_MODE (op1))
     {
-      REAL_VALUE_TYPE f0, f1, value;
+      if (code == AND
+         || code == IOR
+         || code == XOR)
+       {
+         long tmp0[4];
+         long tmp1[4];
+         REAL_VALUE_TYPE r;
+         int i;
+
+         real_to_target (tmp0, CONST_DOUBLE_REAL_VALUE (op0),
+                         GET_MODE (op0));
+         real_to_target (tmp1, CONST_DOUBLE_REAL_VALUE (op1),
+                         GET_MODE (op1));
+         for (i = 0; i < 4; i++)
+           {
+             if (code == AND)
+               tmp0[i] &= tmp1[i];
+             else if (code == IOR)
+               tmp0[i] |= tmp1[i];
+             else if (code == XOR)
+               tmp0[i] ^= tmp1[i];
+             else
+               abort ();
+           }
+          real_from_target (&r, tmp0, mode);
+          return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
+       }
+      else
+       {
+         REAL_VALUE_TYPE f0, f1, value;
 
-      REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0);
-      REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1);
-      f0 = real_value_truncate (mode, f0);
-      f1 = real_value_truncate (mode, f1);
+         REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0);
+         REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1);
+         f0 = real_value_truncate (mode, f0);
+         f1 = real_value_truncate (mode, f1);
 
-      if (HONOR_SNANS (mode)
-         && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
-       return 0;
+         if (HONOR_SNANS (mode)
+             && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
+           return 0;
 
-      if (code == DIV
-         && REAL_VALUES_EQUAL (f1, dconst0)
-         && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
-       return 0;
+         if (code == DIV
+             && REAL_VALUES_EQUAL (f1, dconst0)
+             && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
+           return 0;
 
-      REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
+         REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
 
-      value = real_value_truncate (mode, value);
-      return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
+         value = real_value_truncate (mode, value);
+         return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
+       }
     }
 
   /* We can fold some multi-word operations.  */
@@ -1240,8 +1292,8 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
       && (GET_CODE (trueop1) == CONST_DOUBLE
          || GET_CODE (trueop1) == CONST_INT))
     {
-      unsigned HOST_WIDE_INT l1, l2, lv;
-      HOST_WIDE_INT h1, h2, hv;
+      unsigned HOST_WIDE_INT l1, l2, lv, lt;
+      HOST_WIDE_INT h1, h2, hv, ht;
 
       if (GET_CODE (trueop0) == CONST_DOUBLE)
        l1 = CONST_DOUBLE_LOW (trueop0), h1 = CONST_DOUBLE_HIGH (trueop0);
@@ -1270,10 +1322,29 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
          mul_double (l1, h1, l2, h2, &lv, &hv);
          break;
 
-       case DIV:  case MOD:   case UDIV:  case UMOD:
-         /* We'd need to include tree.h to do this and it doesn't seem worth
-            it.  */
-         return 0;
+       case DIV:
+         if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
+                                   &lv, &hv, &lt, &ht))
+           return 0;
+         break;
+
+       case MOD:
+         if (div_and_round_double (TRUNC_DIV_EXPR, 0, l1, h1, l2, h2,
+                                   &lt, &ht, &lv, &hv))
+           return 0;
+         break;
+
+       case UDIV:
+         if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
+                                   &lv, &hv, &lt, &ht))
+           return 0;
+         break;
+
+       case UMOD:
+         if (div_and_round_double (TRUNC_DIV_EXPR, 1, l1, h1, l2, h2,
+                                   &lt, &ht, &lv, &hv))
+           return 0;
+         break;
 
        case AND:
          lv = l1 & l2, hv = h1 & h2;
@@ -1330,10 +1401,8 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
        case LSHIFTRT:   case ASHIFTRT:
        case ASHIFT:
        case ROTATE:     case ROTATERT:
-#ifdef SHIFT_COUNT_TRUNCATED
          if (SHIFT_COUNT_TRUNCATED)
            l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
-#endif
 
          if (h2 != 0 || l2 >= GET_MODE_BITSIZE (mode))
            return 0;
@@ -1452,6 +1521,17 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
                }
            }
 
+         /* (plus (xor X C1) C2) is (xor X (C1^C2)) if C2 is signbit.  */
+         if ((GET_CODE (op1) == CONST_INT
+              || GET_CODE (op1) == CONST_DOUBLE)
+             && GET_CODE (op0) == XOR
+             && (GET_CODE (XEXP (op0, 1)) == CONST_INT
+                 || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
+             && mode_signbit_p (mode, op1))
+           return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
+                                       simplify_gen_binary (XOR, mode, op1,
+                                                            XEXP (op0, 1)));
+
          /* If one of the operands is a PLUS or a MINUS, see if we can
             simplify this by the associative law.
             Don't use the associative law for floating point.
@@ -1735,9 +1815,27 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
              && ((INTVAL (trueop1) & GET_MODE_MASK (mode))
                  == GET_MODE_MASK (mode)))
            return simplify_gen_unary (NOT, mode, op0, mode);
-         if (trueop0 == trueop1 && ! side_effects_p (op0)
+         if (trueop0 == trueop1
+             && ! side_effects_p (op0)
              && GET_MODE_CLASS (mode) != MODE_CC)
            return const0_rtx;
+
+         /* Canonicalize XOR of the most significant bit to PLUS.  */
+         if ((GET_CODE (op1) == CONST_INT
+              || GET_CODE (op1) == CONST_DOUBLE)
+             && mode_signbit_p (mode, op1))
+           return simplify_gen_binary (PLUS, mode, op0, op1);
+         /* (xor (plus X C1) C2) is (xor X (C1^C2)) if C1 is signbit.  */
+         if ((GET_CODE (op1) == CONST_INT
+              || GET_CODE (op1) == CONST_DOUBLE)
+             && GET_CODE (op0) == PLUS
+             && (GET_CODE (XEXP (op0, 1)) == CONST_INT
+                 || GET_CODE (XEXP (op0, 1)) == CONST_DOUBLE)
+             && mode_signbit_p (mode, XEXP (op0, 1)))
+           return simplify_gen_binary (XOR, mode, XEXP (op0, 0),
+                                       simplify_gen_binary (XOR, mode, op1,
+                                                            XEXP (op0, 1)));
+             
          tem = simplify_associative_operation (code, mode, op0, op1);
          if (tem)
            return tem;
@@ -1765,70 +1863,127 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
          break;
 
        case UDIV:
-         /* Convert divide by power of two into shift (divide by 1 handled
-            below).  */
-         if (GET_CODE (trueop1) == CONST_INT
-             && (arg1 = exact_log2 (INTVAL (trueop1))) > 0)
-           return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (arg1));
-
-         /* Fall through....  */
-
-       case DIV:
-         if (trueop1 == CONST1_RTX (mode))
+         /* 0/x is 0 (or x&0 if x has side-effects).  */
+         if (trueop0 == const0_rtx)
+           return side_effects_p (op1)
+                  ? simplify_gen_binary (AND, mode, op1, const0_rtx)
+                  : const0_rtx;
+         /* x/1 is x.  */
+         if (trueop1 == const1_rtx)
            {
-             /* On some platforms DIV uses narrower mode than its
-                operands.  */
+             /* Handle narrowing UDIV.  */
              rtx x = gen_lowpart_common (mode, op0);
              if (x)
                return x;
-             else if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
+             if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
                return gen_lowpart_SUBREG (mode, op0);
-             else
-               return op0;
+             return op0;
            }
+         /* Convert divide by power of two into shift.  */
+         if (GET_CODE (trueop1) == CONST_INT
+             && (arg1 = exact_log2 (INTVAL (trueop1))) > 0)
+           return simplify_gen_binary (LSHIFTRT, mode, op0, GEN_INT (arg1));
+         break;
 
-         /* Maybe change 0 / x to 0.  This transformation isn't safe for
-            modes with NaNs, since 0 / 0 will then be NaN rather than 0.
-            Nor is it safe for modes with signed zeros, since dividing
-            0 by a negative number gives -0, not 0.  */
-         if (!HONOR_NANS (mode)
-             && !HONOR_SIGNED_ZEROS (mode)
-             && trueop0 == CONST0_RTX (mode)
-             && ! side_effects_p (op1))
-           return op0;
-
-         /* Change division by a constant into multiplication.  Only do
-            this with -funsafe-math-optimizations.  */
-         else if (GET_CODE (trueop1) == CONST_DOUBLE
-                  && GET_MODE_CLASS (GET_MODE (trueop1)) == MODE_FLOAT
-                  && trueop1 != CONST0_RTX (mode)
-                  && flag_unsafe_math_optimizations)
+       case DIV:
+         /* Handle floating point and integers separately.  */
+         if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
-             REAL_VALUE_TYPE d;
-             REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
+             /* Maybe change 0.0 / x to 0.0.  This transformation isn't
+                safe for modes with NaNs, since 0.0 / 0.0 will then be
+                NaN rather than 0.0.  Nor is it safe for modes with signed
+                zeros, since dividing 0 by a negative number gives -0.0  */
+             if (trueop0 == CONST0_RTX (mode)
+                 && !HONOR_NANS (mode)
+                 && !HONOR_SIGNED_ZEROS (mode)
+                 && ! side_effects_p (op1))
+               return op0;
+             /* x/1.0 is x.  */
+             if (trueop1 == CONST1_RTX (mode)
+                 && !HONOR_SNANS (mode))
+               return op0;
 
-             if (! REAL_VALUES_EQUAL (d, dconst0))
+             if (GET_CODE (trueop1) == CONST_DOUBLE
+                 && trueop1 != CONST0_RTX (mode))
+               {
+                 REAL_VALUE_TYPE d;
+                 REAL_VALUE_FROM_CONST_DOUBLE (d, trueop1);
+
+                 /* x/-1.0 is -x.  */
+                 if (REAL_VALUES_EQUAL (d, dconstm1)
+                     && !HONOR_SNANS (mode))
+                   return simplify_gen_unary (NEG, mode, op0, mode);
+
+                 /* Change FP division by a constant into multiplication.
+                    Only do this with -funsafe-math-optimizations.  */
+                 if (flag_unsafe_math_optimizations
+                     && !REAL_VALUES_EQUAL (d, dconst0))
+                   {
+                     REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d);
+                     tem = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
+                     return simplify_gen_binary (MULT, mode, op0, tem);
+                   }
+               }
+           }
+         else
+           {
+             /* 0/x is 0 (or x&0 if x has side-effects).  */
+             if (trueop0 == const0_rtx)
+               return side_effects_p (op1)
+                      ? simplify_gen_binary (AND, mode, op1, const0_rtx)
+                      : const0_rtx;
+             /* x/1 is x.  */
+             if (trueop1 == const1_rtx)
                {
-                 REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
-                 tem = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
-                 return simplify_gen_binary (MULT, mode, op0, tem);
+                 /* Handle narrowing DIV.  */
+                 rtx x = gen_lowpart_common (mode, op0);
+                 if (x)
+                   return x;
+                 if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
+                   return gen_lowpart_SUBREG (mode, op0);
+                 return op0;
+               }
+             /* x/-1 is -x.  */
+             if (trueop1 == constm1_rtx)
+               {
+                 rtx x = gen_lowpart_common (mode, op0);
+                 if (!x)
+                   x = (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
+                       ? gen_lowpart_SUBREG (mode, op0) : op0;
+                 return simplify_gen_unary (NEG, mode, x, mode);
                }
            }
          break;
 
        case UMOD:
-         /* Handle modulus by power of two (mod with 1 handled below).  */
+         /* 0%x is 0 (or x&0 if x has side-effects).  */
+         if (trueop0 == const0_rtx)
+           return side_effects_p (op1)
+                  ? simplify_gen_binary (AND, mode, op1, const0_rtx)
+                  : const0_rtx;
+         /* x%1 is 0 (of x&0 if x has side-effects).  */
+         if (trueop1 == const1_rtx)
+           return side_effects_p (op0)
+                  ? simplify_gen_binary (AND, mode, op0, const0_rtx)
+                  : const0_rtx;
+         /* Implement modulus by power of two as AND.  */
          if (GET_CODE (trueop1) == CONST_INT
              && exact_log2 (INTVAL (trueop1)) > 0)
            return simplify_gen_binary (AND, mode, op0,
                                        GEN_INT (INTVAL (op1) - 1));
-
-         /* Fall through....  */
+         break;
 
        case MOD:
-         if ((trueop0 == const0_rtx || trueop1 == const1_rtx)
-             && ! side_effects_p (op0) && ! side_effects_p (op1))
-           return const0_rtx;
+         /* 0%x is 0 (or x&0 if x has side-effects).  */
+         if (trueop0 == const0_rtx)
+           return side_effects_p (op1)
+                  ? simplify_gen_binary (AND, mode, op1, const0_rtx)
+                  : const0_rtx;
+         /* x%1 and x%-1 is 0 (or x&0 if x has side-effects).  */
+         if (trueop1 == const1_rtx || trueop1 == constm1_rtx)
+           return side_effects_p (op0)
+                  ? simplify_gen_binary (AND, mode, op0, const0_rtx)
+                  : const0_rtx;
          break;
 
        case ROTATERT:
@@ -2113,10 +2268,8 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
       if (arg1 < 0)
        return 0;
 
-#ifdef SHIFT_COUNT_TRUNCATED
       if (SHIFT_COUNT_TRUNCATED)
        arg1 %= width;
-#endif
 
       val = ((unsigned HOST_WIDE_INT) arg0) >> arg1;
       break;
@@ -2125,10 +2278,8 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
       if (arg1 < 0)
        return 0;
 
-#ifdef SHIFT_COUNT_TRUNCATED
       if (SHIFT_COUNT_TRUNCATED)
        arg1 %= width;
-#endif
 
       val = ((unsigned HOST_WIDE_INT) arg0) << arg1;
       break;
@@ -2137,10 +2288,8 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
       if (arg1 < 0)
        return 0;
 
-#ifdef SHIFT_COUNT_TRUNCATED
       if (SHIFT_COUNT_TRUNCATED)
        arg1 %= width;
-#endif
 
       val = arg0s >> arg1;
 
@@ -2476,16 +2625,109 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
 }
 
 /* Like simplify_binary_operation except used for relational operators.
-   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.  */
+   MODE is the mode of the result. If MODE is VOIDmode, both operands must
+   also be VOIDmode.
 
+   CMP_MODE specifies in which mode the comparison is done in, so it is
+   the mode of the operands.  If CMP_MODE is VOIDmode, it is taken from
+   the operands or, if both are VOIDmode, the operands are compared in
+   "infinite precision".  */
 rtx
 simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
-                              rtx op0, rtx op1)
+                              enum machine_mode cmp_mode, rtx op0, rtx op1)
+{
+  rtx tem, trueop0, trueop1;
+
+  if (cmp_mode == VOIDmode)
+    cmp_mode = GET_MODE (op0);
+  if (cmp_mode == VOIDmode)
+    cmp_mode = GET_MODE (op1);
+
+  tem = simplify_const_relational_operation (code, cmp_mode, op0, op1);
+  if (tem)
+    {
+#ifdef FLOAT_STORE_FLAG_VALUE
+      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+       {
+          if (tem == const0_rtx)
+            return CONST0_RTX (mode);
+          else if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+           {
+             REAL_VALUE_TYPE val;
+             val = FLOAT_STORE_FLAG_VALUE (mode);
+             return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
+           }
+       }
+#endif
+
+      return tem;
+    }
+
+  /* For the following tests, ensure const0_rtx is op1.  */
+  if (swap_commutative_operands_p (op0, op1)
+      || (op0 == const0_rtx && op1 != const0_rtx))
+    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
+
+  /* If op0 is a compare, extract the comparison arguments from it.  */
+  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
+    return simplify_relational_operation (code, mode, VOIDmode,
+                                         XEXP (op0, 0), XEXP (op0, 1));
+
+  if (mode == VOIDmode
+      || GET_MODE_CLASS (cmp_mode) == MODE_CC
+      || CC0_P (op0))
+    return NULL_RTX;
+
+  trueop0 = avoid_constant_pool_reference (op0);
+  trueop1 = avoid_constant_pool_reference (op1);
+  return simplify_relational_operation_1 (code, mode, cmp_mode,
+                                         trueop0, trueop1);
+}
+
+/* This part of simplify_relational_operation is only used when CMP_MODE
+   is not in class MODE_CC (i.e. it is a real comparison).
+
+   MODE is the mode of the result, while CMP_MODE specifies in which
+   mode the comparison is done in, so it is the mode of the operands.  */
+rtx
+simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
+                                enum machine_mode cmp_mode, rtx op0, rtx op1)
+{
+  if (GET_CODE (op1) == CONST_INT)
+    {
+      if (INTVAL (op1) == 0 && COMPARISON_P (op0))
+       {
+         /* If op0 is a comparison, extract the comparison arguments form it.  */
+         if (code == NE)
+           {
+             if (GET_MODE (op0) == cmp_mode)
+               return simplify_rtx (op0);
+             else
+               return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
+                                               XEXP (op0, 0), XEXP (op0, 1));
+           }
+         else if (code == EQ)
+           {
+             enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
+             if (new != UNKNOWN)
+               return simplify_gen_relational (new, mode, VOIDmode,
+                                               XEXP (op0, 0), XEXP (op0, 1));
+           }
+       }
+    }
+
+  return NULL_RTX;
+}
+
+/* Check if the given comparison (done in the given MODE) is actually a
+   tautology or a contradiction.
+   If no simplification is possible, this function returns zero.
+   Otherwise, it returns either const_true_rtx or const0_rtx.  */
+
+rtx
+simplify_const_relational_operation (enum rtx_code code,
+                                    enum machine_mode mode,
+                                    rtx op0, rtx op1)
 {
   int equal, op0lt, op0ltu, op1lt, op1ltu;
   rtx tem;
@@ -2524,17 +2766,18 @@ simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
      If CODE is an unsigned comparison, then we can never do this optimization,
      because it gives an incorrect result if the subtraction wraps around zero.
      ANSI C defines unsigned operations such that they never overflow, and
-     thus such cases can not be ignored.  */
+     thus such cases can not be ignored; but we cannot do it even for
+     signed comparisons for languages such as Java, so test flag_wrapv.  */
 
-  if (INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
+  if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
       && ! ((GET_CODE (op0) == REG || GET_CODE (trueop0) == CONST_INT)
            && (GET_CODE (op1) == REG || GET_CODE (trueop1) == CONST_INT))
       && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
       /* We cannot do this for == or != if tem is a nonzero address.  */
       && ((code != EQ && code != NE) || ! nonzero_address_p (tem))
       && code != GTU && code != GEU && code != LTU && code != LEU)
-    return simplify_relational_operation (signed_condition (code),
-                                         mode, tem, const0_rtx);
+    return simplify_const_relational_operation (signed_condition (code),
+                                               mode, tem, const0_rtx);
 
   if (flag_unsafe_math_optimizations && code == ORDERED)
     return const_true_rtx;
@@ -2854,24 +3097,12 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
                  && rtx_equal_p (XEXP (op0, 1), op1))))
        return op2;
 
-      if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
+      if (COMPARISON_P (op0) && ! side_effects_p (op0))
        {
          enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
                                        ? GET_MODE (XEXP (op0, 1))
                                        : GET_MODE (XEXP (op0, 0)));
          rtx temp;
-         if (cmp_mode == VOIDmode)
-           cmp_mode = op0_mode;
-         temp = simplify_relational_operation (GET_CODE (op0), cmp_mode,
-                                               XEXP (op0, 0), XEXP (op0, 1));
-
-         /* See if any simplifications were possible.  */
-         if (temp == const0_rtx)
-           return op2;
-         else if (temp == const_true_rtx)
-           return op1;
-         else if (temp)
-           abort ();
 
          /* Look for happy constants in op1 and op2.  */
          if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
@@ -2892,7 +3123,23 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
              else
                break;
 
-             return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1));
+             return simplify_gen_relational (code, mode, cmp_mode,
+                                             XEXP (op0, 0), XEXP (op0, 1));
+           }
+
+         if (cmp_mode == VOIDmode)
+           cmp_mode = op0_mode;
+         temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
+                                               cmp_mode, XEXP (op0, 0),
+                                               XEXP (op0, 1));
+
+         /* See if any simplifications were possible.  */
+         if (temp)
+           {
+             if (GET_CODE (temp) == CONST_INT)
+               return temp == const0_rtx ? op2 : op1;
+             else if (temp)
+               return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2);
            }
        }
       break;
@@ -3501,48 +3748,38 @@ simplify_rtx (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
-  rtx temp;
 
   switch (GET_RTX_CLASS (code))
     {
-    case '1':
+    case RTX_UNARY:
       return simplify_unary_operation (code, mode,
                                       XEXP (x, 0), GET_MODE (XEXP (x, 0)));
-    case 'c':
+    case RTX_COMM_ARITH:
       if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
        return simplify_gen_binary (code, mode, XEXP (x, 1), XEXP (x, 0));
 
       /* Fall through....  */
 
-    case '2':
+    case RTX_BIN_ARITH:
       return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
 
-    case '3':
-    case 'b':
+    case RTX_TERNARY:
+    case RTX_BITFIELD_OPS:
       return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)),
                                         XEXP (x, 0), XEXP (x, 1),
                                         XEXP (x, 2));
 
-    case '<':
-      temp = simplify_relational_operation (code,
-                                           ((GET_MODE (XEXP (x, 0))
-                                             != VOIDmode)
-                                            ? GET_MODE (XEXP (x, 0))
-                                            : GET_MODE (XEXP (x, 1))),
-                                           XEXP (x, 0), XEXP (x, 1));
-#ifdef FLOAT_STORE_FLAG_VALUE
-      if (temp != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
-       {
-         if (temp == const0_rtx)
-           temp = CONST0_RTX (mode);
-         else
-           temp = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE (mode),
-                                                mode);
-       }
-#endif
-      return temp;
-
-    case 'x':
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
+      return simplify_relational_operation (code, mode,
+                                            ((GET_MODE (XEXP (x, 0))
+                                             != VOIDmode)
+                                            ? GET_MODE (XEXP (x, 0))
+                                            : GET_MODE (XEXP (x, 1))),
+                                            XEXP (x, 0),
+                                            XEXP (x, 1));
+
+    case RTX_EXTRA:
       if (code == SUBREG)
        return simplify_gen_subreg (mode, SUBREG_REG (x),
                                    GET_MODE (SUBREG_REG (x)),
@@ -3554,7 +3791,7 @@ simplify_rtx (rtx x)
        }
       break;
 
-    case 'o':
+    case RTX_OBJ:
       if (code == LO_SUM)
        {
          /* Convert (lo_sum (high FOO) FOO) to FOO.  */