OSDN Git Service

2012-01-30 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / simplify-rtx.c
index bcd55b2..6733b84 100644 (file)
@@ -1,7 +1,7 @@
 /* RTL simplification functions for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011  Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -82,7 +82,7 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
   if (GET_MODE_CLASS (mode) != MODE_INT)
     return false;
 
-  width = GET_MODE_BITSIZE (mode);
+  width = GET_MODE_PRECISION (mode);
   if (width == 0)
     return false;
 
@@ -103,6 +103,62 @@ mode_signbit_p (enum machine_mode mode, const_rtx x)
     val &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
   return val == ((unsigned HOST_WIDE_INT) 1 << (width - 1));
 }
+
+/* Test whether VAL is equal to the most significant bit of mode MODE
+   (after masking with the mode mask of MODE).  Returns false if the
+   precision of MODE is too large to handle.  */
+
+bool
+val_signbit_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+{
+  unsigned int width;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return false;
+
+  width = GET_MODE_PRECISION (mode);
+  if (width == 0 || width > HOST_BITS_PER_WIDE_INT)
+    return false;
+
+  val &= GET_MODE_MASK (mode);
+  return val == ((unsigned HOST_WIDE_INT) 1 << (width - 1));
+}
+
+/* Test whether the most significant bit of mode MODE is set in VAL.
+   Returns false if the precision of MODE is too large to handle.  */
+bool
+val_signbit_known_set_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+{
+  unsigned int width;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return false;
+
+  width = GET_MODE_PRECISION (mode);
+  if (width == 0 || width > HOST_BITS_PER_WIDE_INT)
+    return false;
+
+  val &= (unsigned HOST_WIDE_INT) 1 << (width - 1);
+  return val != 0;
+}
+
+/* Test whether the most significant bit of mode MODE is clear in VAL.
+   Returns false if the precision of MODE is too large to handle.  */
+bool
+val_signbit_known_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+{
+  unsigned int width;
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return false;
+
+  width = GET_MODE_PRECISION (mode);
+  if (width == 0 || width > HOST_BITS_PER_WIDE_INT)
+    return false;
+
+  val &= (unsigned HOST_WIDE_INT) 1 << (width - 1);
+  return val == 0;
+}
 \f
 /* Make a binary operation by properly ordering the operands and
    seeing if the expression folds.  */
@@ -212,7 +268,7 @@ delegitimize_mem_from_attrs (rtx x)
      use their base addresses as equivalent.  */
   if (MEM_P (x)
       && MEM_EXPR (x)
-      && MEM_OFFSET (x))
+      && MEM_OFFSET_KNOWN_P (x))
     {
       tree decl = MEM_EXPR (x);
       enum machine_mode mode = GET_MODE (x);
@@ -265,7 +321,7 @@ delegitimize_mem_from_attrs (rtx x)
        {
          rtx newx;
 
-         offset += INTVAL (MEM_OFFSET (x));
+         offset += MEM_OFFSET (x);
 
          newx = DECL_RTL (decl);
 
@@ -593,7 +649,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
       if (STORE_FLAG_VALUE == -1
          && GET_CODE (op) == ASHIFTRT
          && GET_CODE (XEXP (op, 1))
-         && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
+         && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
        return simplify_gen_relational (GE, mode, VOIDmode,
                                        XEXP (op, 0), const0_rtx);
 
@@ -709,7 +765,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         C is equal to the width of MODE minus 1.  */
       if (GET_CODE (op) == ASHIFTRT
          && CONST_INT_P (XEXP (op, 1))
-         && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
+         && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
        return simplify_gen_binary (LSHIFTRT, mode,
                                    XEXP (op, 0), XEXP (op, 1));
 
@@ -717,7 +773,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
         C is equal to the width of MODE minus 1.  */
       if (GET_CODE (op) == LSHIFTRT
          && CONST_INT_P (XEXP (op, 1))
-         && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
+         && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
        return simplify_gen_binary (ASHIFTRT, mode,
                                    XEXP (op, 0), XEXP (op, 1));
 
@@ -734,14 +790,14 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && SCALAR_INT_MODE_P (GET_MODE (XEXP (op, 0))))
        {
          enum machine_mode inner = GET_MODE (XEXP (op, 0));
-         int isize = GET_MODE_BITSIZE (inner);
+         int isize = GET_MODE_PRECISION (inner);
          if (STORE_FLAG_VALUE == 1)
            {
              temp = simplify_gen_binary (ASHIFTRT, inner, XEXP (op, 0),
                                          GEN_INT (isize - 1));
              if (mode == inner)
                return temp;
-             if (GET_MODE_BITSIZE (mode) > isize)
+             if (GET_MODE_PRECISION (mode) > isize)
                return simplify_gen_unary (SIGN_EXTEND, mode, temp, inner);
              return simplify_gen_unary (TRUNCATE, mode, temp, inner);
            }
@@ -751,7 +807,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
                                          GEN_INT (isize - 1));
              if (mode == inner)
                return temp;
-             if (GET_MODE_BITSIZE (mode) > isize)
+             if (GET_MODE_PRECISION (mode) > isize)
                return simplify_gen_unary (ZERO_EXTEND, mode, temp, inner);
              return simplify_gen_unary (TRUNCATE, mode, temp, inner);
            }
@@ -796,11 +852,10 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          truncation.  But don't do this for an (LSHIFTRT (MULT ...))
          since this will cause problems with the umulXi3_highpart
          patterns.  */
-      if ((TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
-                                GET_MODE_BITSIZE (GET_MODE (op)))
+      if ((TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op))
           ? (num_sign_bit_copies (op, GET_MODE (op))
-             > (unsigned int) (GET_MODE_BITSIZE (GET_MODE (op))
-                               - GET_MODE_BITSIZE (mode)))
+             > (unsigned int) (GET_MODE_PRECISION (GET_MODE (op))
+                               - GET_MODE_PRECISION (mode)))
           : truncated_to_mode (mode, op))
          && ! (GET_CODE (op) == LSHIFTRT
                && GET_CODE (XEXP (op, 0)) == MULT))
@@ -810,7 +865,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          STORE_FLAG_VALUE permits.  This is like the previous test,
          but it works even if the comparison is done in a mode larger
          than HOST_BITS_PER_WIDE_INT.  */
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+      if (HWI_COMPUTABLE_MODE_P (mode)
          && COMPARISON_P (op)
          && (STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
        return rtl_hooks.gen_lowpart_no_emit (mode, op);
@@ -849,7 +904,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          && (flag_unsafe_math_optimizations
              || (SCALAR_FLOAT_MODE_P (GET_MODE (op))
                  && ((unsigned)significand_size (GET_MODE (op))
-                     >= (GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0)))
+                     >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
                          - num_sign_bit_copies (XEXP (op, 0),
                                                 GET_MODE (XEXP (op, 0))))))))
        return simplify_gen_unary (FLOAT, mode,
@@ -886,7 +941,7 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
          || (GET_CODE (op) == FLOAT
              && SCALAR_FLOAT_MODE_P (GET_MODE (op))
              && ((unsigned)significand_size (GET_MODE (op))
-                 >= (GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0)))
+                 >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
                      - num_sign_bit_copies (XEXP (op, 0),
                                             GET_MODE (XEXP (op, 0)))))))
        return simplify_gen_unary (GET_CODE (op), mode,
@@ -908,16 +963,12 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
 
       /* If operand is something known to be positive, ignore the ABS.  */
       if (GET_CODE (op) == FFS || GET_CODE (op) == ABS
-         || ((GET_MODE_BITSIZE (GET_MODE (op))
-              <= HOST_BITS_PER_WIDE_INT)
-             && ((nonzero_bits (op, GET_MODE (op))
-                  & ((unsigned HOST_WIDE_INT) 1
-                     << (GET_MODE_BITSIZE (GET_MODE (op)) - 1)))
-                 == 0)))
+         || val_signbit_known_clear_p (GET_MODE (op),
+                                       nonzero_bits (op, GET_MODE (op))))
        return op;
 
       /* If operand is known to be only -1 or 0, convert ABS to NEG.  */
-      if (num_sign_bit_copies (op, mode) == GET_MODE_BITSIZE (mode))
+      if (num_sign_bit_copies (op, mode) == GET_MODE_PRECISION (mode))
        return gen_rtx_NEG (mode, op);
 
       break;
@@ -1210,8 +1261,8 @@ rtx
 simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
                                rtx op, enum machine_mode op_mode)
 {
-  unsigned int width = GET_MODE_BITSIZE (mode);
-  unsigned int op_width = GET_MODE_BITSIZE (op_mode);
+  unsigned int width = GET_MODE_PRECISION (mode);
+  unsigned int op_width = GET_MODE_PRECISION (op_mode);
 
   if (code == VEC_DUPLICATE)
     {
@@ -1311,7 +1362,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          if (hv < 0)
            return 0;
        }
-      else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
+      else if (GET_MODE_PRECISION (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
        ;
       else
        hv = 0, lv &= GET_MODE_MASK (op_mode);
@@ -1322,8 +1373,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
     }
 
   if (CONST_INT_P (op)
-      && width <= HOST_BITS_PER_WIDE_INT
-      && op_width <= HOST_BITS_PER_WIDE_INT && op_width > 0)
+      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
     {
       HOST_WIDE_INT arg0 = INTVAL (op);
       HOST_WIDE_INT val;
@@ -1343,50 +1393,50 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          break;
 
        case FFS:
-         arg0 &= GET_MODE_MASK (op_mode);
+         arg0 &= GET_MODE_MASK (mode);
          val = ffs_hwi (arg0);
          break;
 
        case CLZ:
-         arg0 &= GET_MODE_MASK (op_mode);
-         if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (op_mode, val))
+         arg0 &= GET_MODE_MASK (mode);
+         if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
            ;
          else
-           val = GET_MODE_BITSIZE (op_mode) - floor_log2 (arg0) - 1;
+           val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
          break;
 
        case CLRSB:
-         arg0 &= GET_MODE_MASK (op_mode);
+         arg0 &= GET_MODE_MASK (mode);
          if (arg0 == 0)
-           val = GET_MODE_BITSIZE (op_mode) - 1;
+           val = GET_MODE_PRECISION (mode) - 1;
          else if (arg0 >= 0)
-           val = GET_MODE_BITSIZE (op_mode) - floor_log2 (arg0) - 2;
+           val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
          else if (arg0 < 0)
-           val = GET_MODE_BITSIZE (op_mode) - floor_log2 (~arg0) - 2;
+           val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
          break;
 
        case CTZ:
-         arg0 &= GET_MODE_MASK (op_mode);
+         arg0 &= GET_MODE_MASK (mode);
          if (arg0 == 0)
            {
              /* Even if the value at zero is undefined, we have to come
                 up with some replacement.  Seems good enough.  */
-             if (! CTZ_DEFINED_VALUE_AT_ZERO (op_mode, val))
-               val = GET_MODE_BITSIZE (op_mode);
+             if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
+               val = GET_MODE_PRECISION (mode);
            }
          else
            val = ctz_hwi (arg0);
          break;
 
        case POPCOUNT:
-         arg0 &= GET_MODE_MASK (op_mode);
+         arg0 &= GET_MODE_MASK (mode);
          val = 0;
          while (arg0)
            val++, arg0 &= arg0 - 1;
          break;
 
        case PARITY:
-         arg0 &= GET_MODE_MASK (op_mode);
+         arg0 &= GET_MODE_MASK (mode);
          val = 0;
          while (arg0)
            val++, arg0 &= arg0 - 1;
@@ -1416,17 +1466,16 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          /* When zero-extending a CONST_INT, we need to know its
              original mode.  */
          gcc_assert (op_mode != VOIDmode);
-         if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
+         if (op_width == HOST_BITS_PER_WIDE_INT)
            {
              /* If we were really extending the mode,
                 we would have to distinguish between zero-extension
                 and sign-extension.  */
-             gcc_assert (width == GET_MODE_BITSIZE (op_mode));
+             gcc_assert (width == op_width);
              val = arg0;
            }
          else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
-           val = arg0 & ~((unsigned HOST_WIDE_INT) (-1)
-                          << GET_MODE_BITSIZE (op_mode));
+           val = arg0 & GET_MODE_MASK (op_mode);
          else
            return 0;
          break;
@@ -1434,23 +1483,20 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
        case SIGN_EXTEND:
          if (op_mode == VOIDmode)
            op_mode = mode;
-         if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
+         op_width = GET_MODE_PRECISION (op_mode);
+         if (op_width == HOST_BITS_PER_WIDE_INT)
            {
              /* If we were really extending the mode,
                 we would have to distinguish between zero-extension
                 and sign-extension.  */
-             gcc_assert (width == GET_MODE_BITSIZE (op_mode));
+             gcc_assert (width == op_width);
              val = arg0;
            }
-         else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
+         else if (op_width < HOST_BITS_PER_WIDE_INT)
            {
-             val
-               = arg0 & ~((unsigned HOST_WIDE_INT) (-1)
-                          << GET_MODE_BITSIZE (op_mode));
-             if (val & ((unsigned HOST_WIDE_INT) 1
-                        << (GET_MODE_BITSIZE (op_mode) - 1)))
-               val
-                 -= (unsigned HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
+             val = arg0 & GET_MODE_MASK (op_mode);
+             if (val_signbit_known_set_p (op_mode, val))
+               val |= ~GET_MODE_MASK (op_mode);
            }
          else
            return 0;
@@ -1519,12 +1565,12 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
        case CLZ:
          hv = 0;
          if (h1 != 0)
-           lv = GET_MODE_BITSIZE (mode) - floor_log2 (h1) - 1
+           lv = GET_MODE_PRECISION (mode) - floor_log2 (h1) - 1
              - HOST_BITS_PER_WIDE_INT;
          else if (l1 != 0)
-           lv = GET_MODE_BITSIZE (mode) - floor_log2 (l1) - 1;
+           lv = GET_MODE_PRECISION (mode) - floor_log2 (l1) - 1;
          else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, lv))
-           lv = GET_MODE_BITSIZE (mode);
+           lv = GET_MODE_PRECISION (mode);
          break;
 
        case CTZ:
@@ -1534,7 +1580,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
          else if (h1 != 0)
            lv = HOST_BITS_PER_WIDE_INT + ctz_hwi (h1);
          else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, lv))
-           lv = GET_MODE_BITSIZE (mode);
+           lv = GET_MODE_PRECISION (mode);
          break;
 
        case POPCOUNT:
@@ -1588,7 +1634,7 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
        case ZERO_EXTEND:
          gcc_assert (op_mode != VOIDmode);
 
-         if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
+         if (op_width > HOST_BITS_PER_WIDE_INT)
            return 0;
 
          hv = 0;
@@ -1597,15 +1643,13 @@ simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
 
        case SIGN_EXTEND:
          if (op_mode == VOIDmode
-             || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
+             || op_width > HOST_BITS_PER_WIDE_INT)
            return 0;
          else
            {
              lv = l1 & GET_MODE_MASK (op_mode);
-             if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
-                 && (lv & ((unsigned HOST_WIDE_INT) 1
-                           << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
-               lv -= (unsigned HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
+             if (val_signbit_known_set_p (op_mode, lv))
+               lv |= ~GET_MODE_MASK (op_mode);
 
              hv = HWI_SIGN_EXTEND (lv);
            }
@@ -1876,7 +1920,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 {
   rtx tem, reversed, opleft, opright;
   HOST_WIDE_INT val;
-  unsigned int width = GET_MODE_BITSIZE (mode);
+  unsigned int width = GET_MODE_PRECISION (mode);
 
   /* Even if we can't compute a constant result,
      there are some cases worth simplifying.  */
@@ -1988,7 +2032,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
              coeff = immed_double_int_const (val, mode);
 
              tem = simplify_gen_binary (MULT, mode, lhs, coeff);
-             return rtx_cost (tem, SET, speed) <= rtx_cost (orig, SET, speed)
+             return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
                ? tem : 0;
            }
        }
@@ -2169,7 +2213,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
              coeff = immed_double_int_const (val, mode);
 
              tem = simplify_gen_binary (MULT, mode, lhs, coeff);
-             return rtx_cost (tem, SET, speed) <= rtx_cost (orig, SET, speed)
+             return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
                ? tem : 0;
            }
        }
@@ -2387,9 +2431,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
     case IOR:
       if (trueop1 == CONST0_RTX (mode))
        return op0;
-      if (CONST_INT_P (trueop1)
-         && ((UINTVAL (trueop1) & GET_MODE_MASK (mode))
-             == GET_MODE_MASK (mode)))
+      if (INTEGRAL_MODE_P (mode) && trueop1 == CONSTM1_RTX (mode))
        return op1;
       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
        return op0;
@@ -2402,7 +2444,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
       /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
       if (CONST_INT_P (op1)
-         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && HWI_COMPUTABLE_MODE_P (mode)
          && (nonzero_bits (op0, mode) & ~UINTVAL (op1)) == 0)
        return op1;
 
@@ -2461,7 +2503,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
           && CONST_INT_P (XEXP (opleft, 1))
           && CONST_INT_P (XEXP (opright, 1))
           && (INTVAL (XEXP (opleft, 1)) + INTVAL (XEXP (opright, 1))
-              == GET_MODE_BITSIZE (mode)))
+              == GET_MODE_PRECISION (mode)))
         return gen_rtx_ROTATE (mode, XEXP (opright, 0), XEXP (opleft, 1));
 
       /* Same, but for ashift that has been "simplified" to a wider mode
@@ -2480,14 +2522,14 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
           && CONST_INT_P (XEXP (SUBREG_REG (opleft), 1))
           && CONST_INT_P (XEXP (opright, 1))
           && (INTVAL (XEXP (SUBREG_REG (opleft), 1)) + INTVAL (XEXP (opright, 1))
-              == GET_MODE_BITSIZE (mode)))
+              == GET_MODE_PRECISION (mode)))
         return gen_rtx_ROTATE (mode, XEXP (opright, 0),
                                XEXP (SUBREG_REG (opleft), 1));
 
       /* If we have (ior (and (X C1) C2)), simplify this by making
         C1 as small as possible if C1 actually changes.  */
       if (CONST_INT_P (op1)
-         && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && (HWI_COMPUTABLE_MODE_P (mode)
              || INTVAL (op1) > 0)
          && GET_CODE (op0) == AND
          && CONST_INT_P (XEXP (op0, 1))
@@ -2529,9 +2571,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
     case XOR:
       if (trueop1 == CONST0_RTX (mode))
        return op0;
-      if (CONST_INT_P (trueop1)
-         && ((UINTVAL (trueop1) & GET_MODE_MASK (mode))
-             == GET_MODE_MASK (mode)))
+      if (INTEGRAL_MODE_P (mode) && trueop1 == CONSTM1_RTX (mode))
        return simplify_gen_unary (NOT, mode, op0, mode);
       if (rtx_equal_p (trueop0, trueop1)
          && ! side_effects_p (op0)
@@ -2558,7 +2598,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
         convert them into an IOR.  This helps to detect rotation encoded
         using those methods and possibly other simplifications.  */
 
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+      if (HWI_COMPUTABLE_MODE_P (mode)
          && (nonzero_bits (op0, mode)
              & nonzero_bits (op1, mode)) == 0)
        return (simplify_gen_binary (IOR, mode, op0, op1));
@@ -2658,14 +2698,12 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          && trueop1 == const1_rtx
          && GET_CODE (op0) == LSHIFTRT
          && CONST_INT_P (XEXP (op0, 1))
-         && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
+         && INTVAL (XEXP (op0, 1)) == GET_MODE_PRECISION (mode) - 1)
        return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
 
       /* (xor (comparison foo bar) (const_int sign-bit))
         when STORE_FLAG_VALUE is the sign bit.  */
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
-             == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
+      if (val_signbit_p (mode, STORE_FLAG_VALUE)
          && trueop1 == const_true_rtx
          && COMPARISON_P (op0)
          && (reversed = reversed_comparison (op0, mode)))
@@ -2679,7 +2717,9 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
     case AND:
       if (trueop1 == CONST0_RTX (mode) && ! side_effects_p (op0))
        return trueop1;
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+      if (INTEGRAL_MODE_P (mode) && trueop1 == CONSTM1_RTX (mode))
+       return op0;
+      if (HWI_COMPUTABLE_MODE_P (mode))
        {
          HOST_WIDE_INT nzop0 = nonzero_bits (trueop0, mode);
          HOST_WIDE_INT nzop1;
@@ -2712,7 +2752,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
       if ((GET_CODE (op0) == SIGN_EXTEND
           || GET_CODE (op0) == ZERO_EXTEND)
          && CONST_INT_P (trueop1)
-         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && HWI_COMPUTABLE_MODE_P (mode)
          && (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
              & UINTVAL (trueop1)) == 0)
        {
@@ -2794,7 +2834,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          Also, if (N & M) == 0, then
         (A +- N) & M -> A & M.  */
       if (CONST_INT_P (trueop1)
-         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && HWI_COMPUTABLE_MODE_P (mode)
          && ~UINTVAL (trueop1)
          && (UINTVAL (trueop1) & (UINTVAL (trueop1) + 1)) == 0
          && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS))
@@ -2913,7 +2953,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
                }
            }
        }
-      else
+      else if (SCALAR_INT_MODE_P (mode))
        {
          /* 0/x is 0 (or x&0 if x has side-effects).  */
          if (trueop0 == CONST0_RTX (mode)
@@ -3019,7 +3059,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
          unsigned HOST_WIDE_INT zero_val = 0;
 
          if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
-             && zero_val == GET_MODE_BITSIZE (imode)
+             && zero_val == GET_MODE_PRECISION (imode)
              && INTVAL (trueop1) == exact_log2 (zero_val))
            return simplify_gen_relational (EQ, mode, imode,
                                            XEXP (op0, 0), const0_rtx);
@@ -3028,8 +3068,7 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
 
     case SMIN:
       if (width <= HOST_BITS_PER_WIDE_INT
-         && CONST_INT_P (trueop1)
-         && UINTVAL (trueop1) == (unsigned HOST_WIDE_INT) 1 << (width -1)
+         && mode_signbit_p (mode, trueop1)
          && ! side_effects_p (op0))
        return op1;
       if (rtx_equal_p (trueop0, trueop1) && ! side_effects_p (op0))
@@ -3310,7 +3349,7 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 {
   HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
   HOST_WIDE_INT val;
-  unsigned int width = GET_MODE_BITSIZE (mode);
+  unsigned int width = GET_MODE_PRECISION (mode);
 
   if (VECTOR_MODE_P (mode)
       && code != VEC_CONCAT
@@ -3595,24 +3634,24 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
            unsigned HOST_WIDE_INT cnt;
 
            if (SHIFT_COUNT_TRUNCATED)
-             o1 = double_int_zext (o1, GET_MODE_BITSIZE (mode));
+             o1 = double_int_zext (o1, GET_MODE_PRECISION (mode));
 
            if (!double_int_fits_in_uhwi_p (o1)
-               || double_int_to_uhwi (o1) >= GET_MODE_BITSIZE (mode))
+               || double_int_to_uhwi (o1) >= GET_MODE_PRECISION (mode))
              return 0;
 
            cnt = double_int_to_uhwi (o1);
 
            if (code == LSHIFTRT || code == ASHIFTRT)
-             res = double_int_rshift (o0, cnt, GET_MODE_BITSIZE (mode),
+             res = double_int_rshift (o0, cnt, GET_MODE_PRECISION (mode),
                                       code == ASHIFTRT);
            else if (code == ASHIFT)
-             res = double_int_lshift (o0, cnt, GET_MODE_BITSIZE (mode),
+             res = double_int_lshift (o0, cnt, GET_MODE_PRECISION (mode),
                                       true);
            else if (code == ROTATE)
-             res = double_int_lrotate (o0, cnt, GET_MODE_BITSIZE (mode));
+             res = double_int_lrotate (o0, cnt, GET_MODE_PRECISION (mode));
            else /* code == ROTATERT */
-             res = double_int_rrotate (o0, cnt, GET_MODE_BITSIZE (mode));
+             res = double_int_rrotate (o0, cnt, GET_MODE_PRECISION (mode));
          }
          break;
 
@@ -3634,16 +3673,16 @@ simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
 
       if (width < HOST_BITS_PER_WIDE_INT)
         {
-          arg0 &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
-          arg1 &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+          arg0 &= GET_MODE_MASK (mode);
+          arg1 &= GET_MODE_MASK (mode);
 
           arg0s = arg0;
-          if (arg0s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
-           arg0s |= ((unsigned HOST_WIDE_INT) (-1) << width);
+         if (val_signbit_known_set_p (mode, arg0s))
+           arg0s |= ~GET_MODE_MASK (mode);
 
-         arg1s = arg1;
-         if (arg1s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
-           arg1s |= ((unsigned HOST_WIDE_INT) (-1) << width);
+          arg1s = arg1;
+         if (val_signbit_known_set_p (mode, arg1s))
+           arg1s |= ~GET_MODE_MASK (mode);
        }
       else
        {
@@ -4313,10 +4352,20 @@ simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
     {
       rtx x = XEXP (op0, 0);
       rtx c = XEXP (op0, 1);
+      enum rtx_code invcode = op0code == PLUS ? MINUS : PLUS;
+      rtx tem = simplify_gen_binary (invcode, cmp_mode, op1, c);
+
+      /* Detect an infinite recursive condition, where we oscillate at this
+        simplification case between:
+           A + B == C  <--->  C - B == A,
+        where A, B, and C are all constants with non-simplifiable expressions,
+        usually SYMBOL_REFs.  */
+      if (GET_CODE (tem) == invcode
+         && CONSTANT_P (x)
+         && rtx_equal_p (c, XEXP (tem, 1)))
+       return NULL_RTX;
 
-      c = simplify_gen_binary (op0code == PLUS ? MINUS : PLUS,
-                              cmp_mode, op1, c);
-      return simplify_gen_relational (code, mode, cmp_mode, x, c);
+      return simplify_gen_relational (code, mode, cmp_mode, x, tem);
     }
 
   /* (ne:SI (zero_extract:SI FOO (const_int 1) BAR) (const_int 0))) is
@@ -4585,7 +4634,7 @@ simplify_const_relational_operation (enum rtx_code code,
        && (GET_CODE (trueop1) == CONST_DOUBLE
           || CONST_INT_P (trueop1)))
     {
-      int width = GET_MODE_BITSIZE (mode);
+      int width = GET_MODE_PRECISION (mode);
       HOST_WIDE_INT l0s, h0s, l1s, h1s;
       unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
 
@@ -4616,14 +4665,14 @@ simplify_const_relational_operation (enum rtx_code code,
         we have to sign or zero-extend the values.  */
       if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
        {
-         l0u &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
-         l1u &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+         l0u &= GET_MODE_MASK (mode);
+         l1u &= GET_MODE_MASK (mode);
 
-         if (l0s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
-           l0s |= ((unsigned HOST_WIDE_INT) (-1) << width);
+         if (val_signbit_known_set_p (mode, l0s))
+           l0s |= ~GET_MODE_MASK (mode);
 
-         if (l1s & ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
-           l1s |= ((unsigned HOST_WIDE_INT) (-1) << width);
+         if (val_signbit_known_set_p (mode, l1s))
+           l1s |= ~GET_MODE_MASK (mode);
        }
       if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
        h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
@@ -4640,8 +4689,7 @@ simplify_const_relational_operation (enum rtx_code code,
     }
 
   /* Optimize comparisons with upper and lower bounds.  */
-  if (SCALAR_INT_MODE_P (mode)
-      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+  if (HWI_COMPUTABLE_MODE_P (mode)
       && CONST_INT_P (trueop1))
     {
       int sign;
@@ -4774,7 +4822,7 @@ simplify_const_relational_operation (enum rtx_code code,
          rtx inner_const = avoid_constant_pool_reference (XEXP (op0, 1));
          if (CONST_INT_P (inner_const) && inner_const != const0_rtx)
            {
-             int sign_bitnum = GET_MODE_BITSIZE (mode) - 1;
+             int sign_bitnum = GET_MODE_PRECISION (mode) - 1;
              int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
                              && (UINTVAL (inner_const)
                                  & ((unsigned HOST_WIDE_INT) 1
@@ -4866,7 +4914,7 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
                            enum machine_mode op0_mode, rtx op0, rtx op1,
                            rtx op2)
 {
-  unsigned int width = GET_MODE_BITSIZE (mode);
+  unsigned int width = GET_MODE_PRECISION (mode);
   bool any_change = false;
   rtx tem;
 
@@ -4911,32 +4959,24 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
        {
          /* Extracting a bit-field from a constant */
          unsigned HOST_WIDE_INT val = UINTVAL (op0);
-
+         HOST_WIDE_INT op1val = INTVAL (op1);
+         HOST_WIDE_INT op2val = INTVAL (op2);
          if (BITS_BIG_ENDIAN)
-           val >>= GET_MODE_BITSIZE (op0_mode) - INTVAL (op2) - INTVAL (op1);
+           val >>= GET_MODE_PRECISION (op0_mode) - op2val - op1val;
          else
-           val >>= INTVAL (op2);
+           val >>= op2val;
 
-         if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
+         if (HOST_BITS_PER_WIDE_INT != op1val)
            {
              /* First zero-extend.  */
-             val &= ((unsigned HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
+             val &= ((unsigned HOST_WIDE_INT) 1 << op1val) - 1;
              /* If desired, propagate sign bit.  */
              if (code == SIGN_EXTRACT
-                 && (val & ((unsigned HOST_WIDE_INT) 1 << (INTVAL (op1) - 1)))
+                 && (val & ((unsigned HOST_WIDE_INT) 1 << (op1val - 1)))
                     != 0)
-               val |= ~ (((unsigned HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
+               val |= ~ (((unsigned HOST_WIDE_INT) 1 << op1val) - 1);
            }
 
-         /* 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 & ((unsigned HOST_WIDE_INT) (-1) << (width - 1)))
-                 != ((unsigned HOST_WIDE_INT) (-1) << (width - 1))))
-           val &= ((unsigned HOST_WIDE_INT) 1 << width) - 1;
-
          return gen_int_mode (val, mode);
        }
       break;
@@ -5579,7 +5619,8 @@ simplify_subreg (enum machine_mode outermode, rtx op,
   /* Optimize SUBREG truncations of zero and sign extended values.  */
   if ((GET_CODE (op) == ZERO_EXTEND
        || GET_CODE (op) == SIGN_EXTEND)
-      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode))
+      && SCALAR_INT_MODE_P (innermode)
+      && GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode))
     {
       unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
 
@@ -5595,7 +5636,7 @@ simplify_subreg (enum machine_mode outermode, rtx op,
          enum machine_mode origmode = GET_MODE (XEXP (op, 0));
          if (outermode == origmode)
            return XEXP (op, 0);
-         if (GET_MODE_BITSIZE (outermode) <= GET_MODE_BITSIZE (origmode))
+         if (GET_MODE_PRECISION (outermode) <= GET_MODE_PRECISION (origmode))
            return simplify_gen_subreg (outermode, XEXP (op, 0), origmode,
                                        subreg_lowpart_offset (outermode,
                                                               origmode));
@@ -5607,7 +5648,7 @@ simplify_subreg (enum machine_mode outermode, rtx op,
       /* A SUBREG resulting from a zero extension may fold to zero if
         it extracts higher bits that the ZERO_EXTEND's source bits.  */
       if (GET_CODE (op) == ZERO_EXTEND
-         && bitpos >= GET_MODE_BITSIZE (GET_MODE (XEXP (op, 0))))
+         && bitpos >= GET_MODE_PRECISION (GET_MODE (XEXP (op, 0))))
        return CONST0_RTX (outermode);
     }
 
@@ -5617,15 +5658,16 @@ simplify_subreg (enum machine_mode outermode, rtx op,
   if ((GET_CODE (op) == LSHIFTRT
        || GET_CODE (op) == ASHIFTRT)
       && SCALAR_INT_MODE_P (outermode)
+      && SCALAR_INT_MODE_P (innermode)
       /* Ensure that OUTERMODE is at least twice as wide as the INNERMODE
         to avoid the possibility that an outer LSHIFTRT shifts by more
         than the sign extension's sign_bit_copies and introduces zeros
         into the high bits of the result.  */
-      && (2 * GET_MODE_BITSIZE (outermode)) <= GET_MODE_BITSIZE (innermode)
+      && (2 * GET_MODE_PRECISION (outermode)) <= GET_MODE_PRECISION (innermode)
       && CONST_INT_P (XEXP (op, 1))
       && GET_CODE (XEXP (op, 0)) == SIGN_EXTEND
       && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
-      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
+      && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
       && subreg_lsb_1 (outermode, innermode, byte) == 0)
     return simplify_gen_binary (ASHIFTRT, outermode,
                                XEXP (XEXP (op, 0), 0), XEXP (op, 1));
@@ -5636,11 +5678,12 @@ simplify_subreg (enum machine_mode outermode, rtx op,
   if ((GET_CODE (op) == LSHIFTRT
        || GET_CODE (op) == ASHIFTRT)
       && SCALAR_INT_MODE_P (outermode)
-      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
+      && SCALAR_INT_MODE_P (innermode)
+      && GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
       && CONST_INT_P (XEXP (op, 1))
       && GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
       && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
-      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
+      && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
       && subreg_lsb_1 (outermode, innermode, byte) == 0)
     return simplify_gen_binary (LSHIFTRT, outermode,
                                XEXP (XEXP (op, 0), 0), XEXP (op, 1));
@@ -5650,12 +5693,13 @@ simplify_subreg (enum machine_mode outermode, rtx op,
      the outer subreg is effectively a truncation to the original mode.  */
   if (GET_CODE (op) == ASHIFT
       && SCALAR_INT_MODE_P (outermode)
-      && GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
+      && SCALAR_INT_MODE_P (innermode)
+      && GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
       && CONST_INT_P (XEXP (op, 1))
       && (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
          || GET_CODE (XEXP (op, 0)) == SIGN_EXTEND)
       && GET_MODE (XEXP (XEXP (op, 0), 0)) == outermode
-      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (outermode)
+      && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (outermode)
       && subreg_lsb_1 (outermode, innermode, byte) == 0)
     return simplify_gen_binary (ASHIFT, outermode,
                                XEXP (XEXP (op, 0), 0), XEXP (op, 1));
@@ -5663,13 +5707,13 @@ simplify_subreg (enum machine_mode outermode, rtx op,
   /* Recognize a word extraction from a multi-word subreg.  */
   if ((GET_CODE (op) == LSHIFTRT
        || GET_CODE (op) == ASHIFTRT)
-      && SCALAR_INT_MODE_P (outermode)
-      && GET_MODE_BITSIZE (outermode) >= BITS_PER_WORD
-      && GET_MODE_BITSIZE (innermode) >= (2 * GET_MODE_BITSIZE (outermode))
+      && SCALAR_INT_MODE_P (innermode)
+      && GET_MODE_PRECISION (outermode) >= BITS_PER_WORD
+      && GET_MODE_PRECISION (innermode) >= (2 * GET_MODE_PRECISION (outermode))
       && CONST_INT_P (XEXP (op, 1))
-      && (INTVAL (XEXP (op, 1)) & (GET_MODE_BITSIZE (outermode) - 1)) == 0
+      && (INTVAL (XEXP (op, 1)) & (GET_MODE_PRECISION (outermode) - 1)) == 0
       && INTVAL (XEXP (op, 1)) >= 0
-      && INTVAL (XEXP (op, 1)) < GET_MODE_BITSIZE (innermode)
+      && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (innermode)
       && byte == subreg_lowpart_offset (outermode, innermode))
     {
       int shifted_bytes = INTVAL (XEXP (op, 1)) / BITS_PER_UNIT;
@@ -5685,6 +5729,7 @@ simplify_subreg (enum machine_mode outermode, rtx op,
 
   if ((GET_CODE (op) == LSHIFTRT
        || GET_CODE (op) == ASHIFTRT)
+      && SCALAR_INT_MODE_P (innermode)
       && MEM_P (XEXP (op, 0))
       && CONST_INT_P (XEXP (op, 1))
       && GET_MODE_SIZE (outermode) < GET_MODE_SIZE (GET_MODE (op))