OSDN Git Service

* java-tree.def (THIS_EXPR): Now a tcc_expression.
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 0e414bc..5671682 100644 (file)
@@ -1,6 +1,6 @@
 /* Fold a constant sub-tree into a single node for C-compiler
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -108,6 +108,8 @@ static int all_ones_mask_p (tree, int);
 static tree sign_bit_p (tree, tree);
 static int simple_operand_p (tree);
 static tree range_binop (enum tree_code, tree, tree, int, tree, int);
+static tree range_predecessor (tree);
+static tree range_successor (tree);
 static tree make_range (tree, int *, tree *, tree *);
 static tree build_range_check (tree, tree, int, tree, tree);
 static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree,
@@ -132,7 +134,9 @@ static bool reorder_operands_p (tree, tree);
 static tree fold_negate_const (tree, tree);
 static tree fold_not_const (tree, tree);
 static tree fold_relational_const (enum tree_code, tree, tree, tree);
-static bool tree_expr_nonzero_p (tree);
+static int native_encode_expr (tree, unsigned char *, int);
+static tree native_interpret_expr (tree, unsigned char *, int);
+
 
 /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
    overflow.  Suppose A, B and SUM have the same respective signs as A1, B1,
@@ -858,26 +862,23 @@ div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2)
   return build_int_cst_wide (type, quol, quoh);
 }
 \f
-/* Return true if built-in mathematical function specified by CODE
-   preserves the sign of it argument, i.e. -f(x) == f(-x).  */
+/* Return true if the built-in mathematical function specified by CODE
+   is odd, i.e. -f(x) == f(-x).  */
 
 static bool
 negate_mathfn_p (enum built_in_function code)
 {
   switch (code)
     {
-    case BUILT_IN_ASIN:
-    case BUILT_IN_ASINF:
-    case BUILT_IN_ASINL:
-    case BUILT_IN_ATAN:
-    case BUILT_IN_ATANF:
-    case BUILT_IN_ATANL:
-    case BUILT_IN_SIN:
-    case BUILT_IN_SINF:
-    case BUILT_IN_SINL:
-    case BUILT_IN_TAN:
-    case BUILT_IN_TANF:
-    case BUILT_IN_TANL:
+    CASE_FLT_FN (BUILT_IN_ASIN):
+    CASE_FLT_FN (BUILT_IN_ASINH):
+    CASE_FLT_FN (BUILT_IN_ATAN):
+    CASE_FLT_FN (BUILT_IN_ATANH):
+    CASE_FLT_FN (BUILT_IN_CBRT):
+    CASE_FLT_FN (BUILT_IN_SIN):
+    CASE_FLT_FN (BUILT_IN_SINH):
+    CASE_FLT_FN (BUILT_IN_TAN):
+    CASE_FLT_FN (BUILT_IN_TANH):
       return true;
 
     default:
@@ -939,6 +940,8 @@ negate_expr_p (tree t)
 
       /* Check that -CST will not overflow type.  */
       return may_negate_without_overflow_p (t);
+    case BIT_NOT_EXPR:
+       return INTEGRAL_TYPE_P (type);
 
     case REAL_CST:
     case NEGATE_EXPR:
@@ -977,6 +980,16 @@ negate_expr_p (tree t)
               || negate_expr_p (TREE_OPERAND (t, 0));
       break;
 
+    case TRUNC_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      if (TYPE_UNSIGNED (TREE_TYPE (t)) || flag_wrapv)
+        break;
+      return negate_expr_p (TREE_OPERAND (t, 1))
+             || negate_expr_p (TREE_OPERAND (t, 0));
+
     case NOP_EXPR:
       /* Negate -((double)float) as (double)(-float).  */
       if (TREE_CODE (type) == REAL_TYPE)
@@ -1028,6 +1041,13 @@ negate_expr (tree t)
 
   switch (TREE_CODE (t))
     {
+    /* Convert - (~A) to A + 1.  */
+    case BIT_NOT_EXPR:
+      if (INTEGRAL_TYPE_P (type))
+        return fold_build2 (PLUS_EXPR, type, TREE_OPERAND (t, 0),
+                            build_int_cst (type, 1));
+      break;
+      
     case INTEGER_CST:
       tem = fold_negate_const (t, type);
       if (! TREE_OVERFLOW (tem)
@@ -1118,6 +1138,28 @@ negate_expr (tree t)
        }
       break;
 
+    case TRUNC_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      if (!TYPE_UNSIGNED (TREE_TYPE (t)) && !flag_wrapv)
+        {
+          tem = TREE_OPERAND (t, 1);
+          if (negate_expr_p (tem))
+            return fold_convert (type,
+                                 fold_build2 (TREE_CODE (t), TREE_TYPE (t),
+                                              TREE_OPERAND (t, 0),
+                                              negate_expr (tem)));
+          tem = TREE_OPERAND (t, 0);
+          if (negate_expr_p (tem))
+            return fold_convert (type,
+                                 fold_build2 (TREE_CODE (t), TREE_TYPE (t),
+                                              negate_expr (tem),
+                                              TREE_OPERAND (t, 1)));
+        }
+      break;
+
     case NOP_EXPR:
       /* Convert -((double)float) into (double)(-float).  */
       if (TREE_CODE (type) == REAL_TYPE)
@@ -1308,7 +1350,8 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type)
 }
 \f
 /* Combine two integer constants ARG1 and ARG2 under operation CODE
-   to produce a new constant.
+   to produce a new constant.  Return NULL_TREE if we don't know how
+   to evaluate CODE at compile-time.
 
    If NOTRUNC is nonzero, do not truncate the result to fit the data type.  */
 
@@ -1397,6 +1440,8 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       /* ... fall through ...  */
 
     case ROUND_DIV_EXPR:
+      if (int2h == 0 && int2l == 0)
+       return NULL_TREE;
       if (int2h == 0 && int2l == 1)
        {
          low = int1l, hi = int1h;
@@ -1429,6 +1474,8 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       /* ... fall through ...  */
 
     case ROUND_MOD_EXPR:
+      if (int2h == 0 && int2l == 0)
+       return NULL_TREE;
       overflow = div_and_round_double (code, uns,
                                       int1l, int1h, int2l, int2h,
                                       &garbagel, &garbageh, &low, &hi);
@@ -1453,7 +1500,7 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       break;
 
     default:
-      gcc_unreachable ();
+      return NULL_TREE;
     }
 
   t = build_int_cst_wide (TREE_TYPE (arg1), low, hi);
@@ -1509,6 +1556,21 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       bool inexact;
       tree t, type;
 
+      /* The following codes are handled by real_arithmetic.  */
+      switch (code)
+       {
+       case PLUS_EXPR:
+       case MINUS_EXPR:
+       case MULT_EXPR:
+       case RDIV_EXPR:
+       case MIN_EXPR:
+       case MAX_EXPR:
+         break;
+
+       default:
+         return NULL_TREE;
+       }
+
       d1 = TREE_REAL_CST (arg1);
       d2 = TREE_REAL_CST (arg2);
 
@@ -1538,6 +1600,16 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       inexact = real_arithmetic (&value, code, &d1, &d2);
       real_convert (&result, mode, &value);
 
+      /* Don't constant fold this floating point operation if
+        the result has overflowed and flag_trapping_math.  */
+
+      if (flag_trapping_math
+         && MODE_HAS_INFINITIES (mode)
+         && REAL_VALUE_ISINF (result)
+         && !REAL_VALUE_ISINF (d1)
+         && !REAL_VALUE_ISINF (d2))
+       return NULL_TREE;
+
       /* Don't constant fold this floating point operation if the
         result may dependent upon the run-time rounding mode and
         flag_rounding_math is set, or if GCC's software emulation
@@ -1558,6 +1630,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
          | TREE_CONSTANT_OVERFLOW (arg2);
       return t;
     }
+
   if (TREE_CODE (arg1) == COMPLEX_CST)
     {
       tree type = TREE_TYPE (arg1);
@@ -1633,11 +1706,11 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
          break;
 
        default:
-         gcc_unreachable ();
+         return NULL_TREE;
        }
       return t;
     }
-  return 0;
+  return NULL_TREE;
 }
 
 /* Create a size type INT_CST node with NUMBER sign extended.  KIND
@@ -1715,11 +1788,11 @@ size_diffop (tree arg0, tree arg1)
      overflow) and negate (which can't either).  Special-case a result
      of zero while we're here.  */
   if (tree_int_cst_equal (arg0, arg1))
-    return fold_convert (ctype, integer_zero_node);
+    return build_int_cst (ctype, 0);
   else if (tree_int_cst_lt (arg1, arg0))
     return fold_convert (ctype, size_binop (MINUS_EXPR, arg0, arg1));
   else
-    return size_binop (MINUS_EXPR, fold_convert (ctype, integer_zero_node),
+    return size_binop (MINUS_EXPR, build_int_cst (ctype, 0),
                       fold_convert (ctype, size_binop (MINUS_EXPR,
                                                        arg1, arg0)));
 }
@@ -1927,7 +2000,7 @@ fold_convert (tree type, tree arg)
 
   switch (TREE_CODE (type))
     {
-    case INTEGER_TYPE: case CHAR_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
+    case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
     case POINTER_TYPE: case REFERENCE_TYPE:
     case OFFSET_TYPE:
       if (TREE_CODE (arg) == INTEGER_CST)
@@ -1964,14 +2037,13 @@ fold_convert (tree type, tree arg)
 
       switch (TREE_CODE (orig))
        {
-       case INTEGER_TYPE: case CHAR_TYPE:
+       case INTEGER_TYPE:
        case BOOLEAN_TYPE: case ENUMERAL_TYPE:
        case POINTER_TYPE: case REFERENCE_TYPE:
          return fold_build1 (FLOAT_EXPR, type, arg);
 
        case REAL_TYPE:
-         return fold_build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
-                             type, arg);
+         return fold_build1 (NOP_EXPR, type, arg);
 
        case COMPLEX_TYPE:
          tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg);
@@ -1984,7 +2056,7 @@ fold_convert (tree type, tree arg)
     case COMPLEX_TYPE:
       switch (TREE_CODE (orig))
        {
-       case INTEGER_TYPE: case CHAR_TYPE:
+       case INTEGER_TYPE:
        case BOOLEAN_TYPE: case ENUMERAL_TYPE:
        case POINTER_TYPE: case REFERENCE_TYPE:
        case REAL_TYPE:
@@ -2020,17 +2092,17 @@ fold_convert (tree type, tree arg)
       gcc_assert (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)));
       gcc_assert (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig)
                  || TREE_CODE (orig) == VECTOR_TYPE);
-      return fold_build1 (NOP_EXPR, type, arg);
+      return fold_build1 (VIEW_CONVERT_EXPR, type, arg);
 
     case VOID_TYPE:
-      return fold_build1 (CONVERT_EXPR, type, fold_ignored_result (arg));
+      return fold_build1 (NOP_EXPR, type, fold_ignored_result (arg));
 
     default:
       gcc_unreachable ();
     }
 }
 \f
-/* Return false if expr can be assumed not to be an value, true
+/* Return false if expr can be assumed not to be an lvalue, true
    otherwise.  */
 
 static bool
@@ -2568,8 +2640,11 @@ operand_equal_p (tree arg0, tree arg1, unsigned int flags)
                  && OP_SAME_WITH_NULL (3));
 
        case COMPONENT_REF:
-         /* Handle operand 2 the same as for ARRAY_REF.  */
-         return OP_SAME (0) && OP_SAME (1) && OP_SAME_WITH_NULL (2);
+         /* Handle operand 2 the same as for ARRAY_REF.  Operand 0
+            may be NULL when we're called to compare MEM_EXPRs.  */
+         return OP_SAME_WITH_NULL (0)
+                && OP_SAME (1)
+                && OP_SAME_WITH_NULL (2);
 
        case BIT_FIELD_REF:
          return OP_SAME (0) && OP_SAME (1) && OP_SAME (2);
@@ -3026,9 +3101,18 @@ invert_truthvalue (tree arg)
       return TREE_OPERAND (arg, 0);
 
     case COND_EXPR:
-      return build3 (COND_EXPR, type, TREE_OPERAND (arg, 0),
-                    invert_truthvalue (TREE_OPERAND (arg, 1)),
-                    invert_truthvalue (TREE_OPERAND (arg, 2)));
+      {
+       tree arg1 = TREE_OPERAND (arg, 1);
+       tree arg2 = TREE_OPERAND (arg, 2);
+       /* A COND_EXPR may have a throw as one operand, which
+          then has void type.  Just leave void operands
+          as they are.  */
+       return build3 (COND_EXPR, type, TREE_OPERAND (arg, 0),
+                      VOID_TYPE_P (TREE_TYPE (arg1))
+                      ? arg1 : invert_truthvalue (arg1),
+                      VOID_TYPE_P (TREE_TYPE (arg2))
+                      ? arg2 : invert_truthvalue (arg2));
+      }
 
     case COMPOUND_EXPR:
       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg, 0),
@@ -3050,7 +3134,7 @@ invert_truthvalue (tree arg)
       if (!integer_onep (TREE_OPERAND (arg, 1)))
        break;
       return build2 (EQ_EXPR, type, arg,
-                    fold_convert (type, integer_zero_node));
+                    build_int_cst (type, 0));
 
     case SAVE_EXPR:
       return build1 (TRUTH_NOT_EXPR, type, arg);
@@ -3328,7 +3412,7 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
   if (lbitsize == 1 && ! integer_zerop (rhs))
     {
       code = code == EQ_EXPR ? NE_EXPR : EQ_EXPR;
-      rhs = fold_convert (type, integer_zero_node);
+      rhs = build_int_cst (type, 0);
     }
 
   /* Make a new bitfield reference, shift the constant over the
@@ -3341,11 +3425,11 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
       TREE_THIS_VOLATILE (lhs) = 1;
     }
 
-  rhs = fold (const_binop (BIT_AND_EXPR,
-                          const_binop (LSHIFT_EXPR,
-                                       fold_convert (unsigned_type, rhs),
-                                       size_int (lbitpos), 0),
-                          mask, 0));
+  rhs = const_binop (BIT_AND_EXPR,
+                    const_binop (LSHIFT_EXPR,
+                                 fold_convert (unsigned_type, rhs),
+                                 size_int (lbitpos), 0),
+                    mask, 0);
 
   return build2 (code, compare_type,
                 build2 (BIT_AND_EXPR, unsigned_type, lhs, mask),
@@ -3665,7 +3749,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
      the switch, which will "break" the while.  */
 
   in_p = 0;
-  low = high = fold_convert (TREE_TYPE (exp), integer_zero_node);
+  low = high = build_int_cst (TREE_TYPE (exp), 0);
 
   while (1)
     {
@@ -3738,7 +3822,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
            {
              if (! merge_ranges (&n_in_p, &n_low, &n_high,
                                  in_p, low, high, 1,
-                                 fold_convert (arg0_type, integer_zero_node),
+                                 build_int_cst (arg0_type, 0),
                                  NULL_TREE))
                break;
 
@@ -3752,7 +3836,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
                  in_p = ! in_p;
                  high = range_binop (MINUS_EXPR, NULL_TREE, low, 0,
                                      integer_one_node, 0);
-                 low = fold_convert (arg0_type, integer_zero_node);
+                 low = build_int_cst (arg0_type, 0);
                }
            }
 
@@ -3762,10 +3846,10 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
        case NEGATE_EXPR:
          /* (-x) IN [a,b] -> x in [-b, -a]  */
          n_low = range_binop (MINUS_EXPR, exp_type,
-                              fold_convert (exp_type, integer_zero_node),
+                              build_int_cst (exp_type, 0),
                               0, high, 1);
          n_high = range_binop (MINUS_EXPR, exp_type,
-                               fold_convert (exp_type, integer_zero_node),
+                               build_int_cst (exp_type, 0),
                                0, low, 0);
          low = n_low, high = n_high;
          exp = arg0;
@@ -3774,13 +3858,18 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
        case BIT_NOT_EXPR:
          /* ~ X -> -X - 1  */
          exp = build2 (MINUS_EXPR, exp_type, negate_expr (arg0),
-                       fold_convert (exp_type, integer_one_node));
+                       build_int_cst (exp_type, 1));
          continue;
 
        case PLUS_EXPR:  case MINUS_EXPR:
          if (TREE_CODE (arg1) != INTEGER_CST)
            break;
 
+         /* If flag_wrapv and ARG0_TYPE is signed, then we cannot
+            move a constant to the other side.  */
+         if (flag_wrapv && !TYPE_UNSIGNED (arg0_type))
+           break;
+
          /* If EXP is signed, any overflow in the computation is undefined,
             so we don't worry about it so long as our computations on
             the bounds don't overflow.  For unsigned, overflow is defined
@@ -3930,6 +4019,15 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
   tree etype = TREE_TYPE (exp);
   tree value;
 
+#ifdef HAVE_canonicalize_funcptr_for_compare
+  /* Disable this optimization for function pointer expressions
+     on targets that require function pointer canonicalization.  */
+  if (HAVE_canonicalize_funcptr_for_compare
+      && TREE_CODE (etype) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (etype)) == FUNCTION_TYPE)
+    return NULL_TREE;
+#endif
+
   if (! in_p)
     {
       value = build_range_check (type, exp, 1, low, high);
@@ -3940,7 +4038,7 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
     }
 
   if (low == 0 && high == 0)
-    return fold_convert (type, integer_one_node);
+    return build_int_cst (type, 1);
 
   if (low == 0)
     return fold_build2 (LE_EXPR, type, exp,
@@ -3992,51 +4090,95 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
              exp = fold_convert (etype, exp);
            }
          return fold_build2 (GT_EXPR, type, exp,
-                             fold_convert (etype, integer_zero_node));
+                             build_int_cst (etype, 0));
        }
     }
 
-  value = const_binop (MINUS_EXPR, high, low, 0);
-  if (value != 0 && TREE_OVERFLOW (value) && ! TYPE_UNSIGNED (etype))
+  /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low).
+     This requires wrap-around arithmetics for the type of the expression.  */
+  switch (TREE_CODE (etype))
+    {
+    case INTEGER_TYPE:
+      /* There is no requirement that LOW be within the range of ETYPE
+        if the latter is a subtype.  It must, however, be within the base
+        type of ETYPE.  So be sure we do the subtraction in that type.  */
+      if (TREE_TYPE (etype))
+       etype = TREE_TYPE (etype);
+      break;
+
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+      etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
+                                             TYPE_UNSIGNED (etype));
+      break;
+
+    default:
+      break;
+    }
+
+  /* If we don't have wrap-around arithmetics upfront, try to force it.  */
+  if (TREE_CODE (etype) == INTEGER_TYPE
+      && !TYPE_UNSIGNED (etype) && !flag_wrapv)
     {
       tree utype, minv, maxv;
 
       /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN
         for the type in question, as we rely on this here.  */
-      switch (TREE_CODE (etype))
-       {
-       case INTEGER_TYPE:
-       case ENUMERAL_TYPE:
-       case CHAR_TYPE:
-         utype = lang_hooks.types.unsigned_type (etype);
-         maxv = fold_convert (utype, TYPE_MAX_VALUE (etype));
-         maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1,
-                             integer_one_node, 1);
-         minv = fold_convert (utype, TYPE_MIN_VALUE (etype));
-         if (integer_zerop (range_binop (NE_EXPR, integer_type_node,
-                                         minv, 1, maxv, 1)))
-           {
-             etype = utype;
-             high = fold_convert (etype, high);
-             low = fold_convert (etype, low);
-             exp = fold_convert (etype, exp);
-             value = const_binop (MINUS_EXPR, high, low, 0);
-           }
-         break;
-       default:
-         break;
-       }
+      utype = lang_hooks.types.unsigned_type (etype);
+      maxv = fold_convert (utype, TYPE_MAX_VALUE (etype));
+      maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1,
+                         integer_one_node, 1);
+      minv = fold_convert (utype, TYPE_MIN_VALUE (etype));
+
+      if (integer_zerop (range_binop (NE_EXPR, integer_type_node,
+                                     minv, 1, maxv, 1)))
+       etype = utype;
+      else
+       return 0;
     }
 
-  if (value != 0 && ! TREE_OVERFLOW (value))
+  high = fold_convert (etype, high);
+  low = fold_convert (etype, low);
+  exp = fold_convert (etype, exp);
+
+  value = const_binop (MINUS_EXPR, high, low, 0);
+
+  if (value != 0 && !TREE_OVERFLOW (value))
     return build_range_check (type,
                              fold_build2 (MINUS_EXPR, etype, exp, low),
-                             1, fold_convert (etype, integer_zero_node),
-                             value);
+                             1, build_int_cst (etype, 0), value);
 
   return 0;
 }
 \f
+/* Return the predecessor of VAL in its type, handling the infinite case.  */
+
+static tree
+range_predecessor (tree val)
+{
+  tree type = TREE_TYPE (val);
+
+  if (INTEGRAL_TYPE_P (type)
+      && operand_equal_p (val, TYPE_MIN_VALUE (type), 0))
+    return 0;
+  else
+    return range_binop (MINUS_EXPR, NULL_TREE, val, 0, integer_one_node, 0);
+}
+
+/* Return the successor of VAL in its type, handling the infinite case.  */
+
+static tree
+range_successor (tree val)
+{
+  tree type = TREE_TYPE (val);
+
+  if (INTEGRAL_TYPE_P (type)
+      && operand_equal_p (val, TYPE_MAX_VALUE (type), 0))
+    return 0;
+  else
+    return range_binop (PLUS_EXPR, NULL_TREE, val, 0, integer_one_node, 0);
+}
+
 /* Given two ranges, see if we can merge them into one.  Return 1 if we
    can, 0 if we can't.  Set the output range into the specified parameters.  */
 
@@ -4098,7 +4240,7 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
       /* If they don't overlap, the result is the first range.  If they are
         equal, the result is false.  If the second range is a subset of the
         first, and the ranges begin at the same place, we go from just after
-        the end of the first range to the end of the second.  If the second
+        the end of the second range to the end of the first.  If the second
         range is not a subset of the first, or if it is a subset and both
         ranges end at the same place, the range starts at the start of the
         first range and ends just before the second range.
@@ -4109,15 +4251,15 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
        in_p = 0, low = high = 0;
       else if (subset && lowequal)
        {
-         in_p = 1, high = high0;
-         low = range_binop (PLUS_EXPR, NULL_TREE, high1, 0,
-                            integer_one_node, 0);
+         low = range_successor (high1);
+         high = high0;
+         in_p = (low != 0);
        }
       else if (! subset || highequal)
        {
-         in_p = 1, low = low0;
-         high = range_binop (MINUS_EXPR, NULL_TREE, low1, 0,
-                             integer_one_node, 0);
+         low = low0;
+         high = range_predecessor (low1);
+         in_p = (high != 0);
        }
       else
        return 0;
@@ -4135,9 +4277,9 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
        in_p = 0, low = high = 0;
       else
        {
-         in_p = 1, high = high1;
-         low = range_binop (PLUS_EXPR, NULL_TREE, high0, 1,
-                            integer_one_node, 0);
+         low = range_successor (high0);
+         high = high1;
+         in_p = (low != 0);
        }
     }
 
@@ -4152,9 +4294,7 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
       if (no_overlap)
        {
          if (integer_onep (range_binop (EQ_EXPR, integer_type_node,
-                                        range_binop (PLUS_EXPR, NULL_TREE,
-                                                     high0, 1,
-                                                     integer_one_node, 1),
+                                        range_successor (high0),
                                         1, low1, 0)))
            in_p = 0, low = low0, high = high1;
          else
@@ -4169,7 +4309,6 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
                      break;
                    /* FALLTHROUGH */
                  case INTEGER_TYPE:
-                 case CHAR_TYPE:
                    if (tree_int_cst_equal (low0,
                                            TYPE_MIN_VALUE (TREE_TYPE (low0))))
                      low0 = 0;
@@ -4193,7 +4332,6 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
                      break;
                    /* FALLTHROUGH */
                  case INTEGER_TYPE:
-                 case CHAR_TYPE:
                    if (tree_int_cst_equal (high1,
                                            TYPE_MAX_VALUE (TREE_TYPE (high1))))
                      high1 = 0;
@@ -4215,10 +4353,8 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
                 return + [x + 1, y - 1].  */
              if (low0 == 0 && high1 == 0)
                {
-                 low = range_binop (PLUS_EXPR, NULL_TREE, high0, 1,
-                                    integer_one_node, 1);
-                 high = range_binop (MINUS_EXPR, NULL_TREE, low1, 0,
-                                     integer_one_node, 0);
+                 low = range_successor (high0);
+                 high = range_predecessor (low1);
                  if (low == 0 || high == 0)
                    return 0;
 
@@ -4338,7 +4474,7 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
       if (comp_code == NE_EXPR)
        return pedantic_non_lvalue (fold_convert (type, arg1));
       else if (comp_code == EQ_EXPR)
-       return fold_convert (type, integer_zero_node);
+       return build_int_cst (type, 0);
     }
 
   /* Try some transformations of A op B ? A : B.
@@ -4695,14 +4831,14 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
   if (lcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (lhs, 1)))
     {
       lhs = build2 (NE_EXPR, truth_type, lhs,
-                   fold_convert (TREE_TYPE (lhs), integer_zero_node));
+                   build_int_cst (TREE_TYPE (lhs), 0));
       lcode = NE_EXPR;
     }
 
   if (rcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (rhs, 1)))
     {
       rhs = build2 (NE_EXPR, truth_type, rhs,
-                   fold_convert (TREE_TYPE (rhs), integer_zero_node));
+                   build_int_cst (TREE_TYPE (rhs), 0));
       rcode = NE_EXPR;
     }
 
@@ -4761,7 +4897,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
        return build2 (NE_EXPR, truth_type,
                       build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
                               ll_arg, rl_arg),
-                      fold_convert (TREE_TYPE (ll_arg), integer_zero_node));
+                      build_int_cst (TREE_TYPE (ll_arg), 0));
 
       /* Convert (a == 0) && (b == 0) into (a | b) == 0.  */
       if (code == TRUTH_AND_EXPR
@@ -4771,7 +4907,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
        return build2 (EQ_EXPR, truth_type,
                       build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
                               ll_arg, rl_arg),
-                      fold_convert (TREE_TYPE (ll_arg), integer_zero_node));
+                      build_int_cst (TREE_TYPE (ll_arg), 0));
 
       if (LOGICAL_OP_NON_SHORT_CIRCUIT)
        return build2 (code, truth_type, lhs, rhs);
@@ -5504,7 +5640,8 @@ constant_boolean_node (int value, tree type)
    offset to the appropriate trees.  If there is no offset,
    offset is set to NULL_TREE.  Base will be canonicalized to
    something you can get the element type from using
-   TREE_TYPE (TREE_TYPE (base)).  */
+   TREE_TYPE (TREE_TYPE (base)).  Offset will be the offset
+   in bytes to the base.  */
 
 static bool
 extract_array_ref (tree expr, tree *base, tree *offset)
@@ -5540,8 +5677,10 @@ extract_array_ref (tree expr, tree *base, tree *offset)
       tree op0 = TREE_OPERAND (expr, 0);
       if (TREE_CODE (op0) == ARRAY_REF)
        {
+         tree idx = TREE_OPERAND (op0, 1);
          *base = TREE_OPERAND (op0, 0);
-         *offset = TREE_OPERAND (op0, 1);
+         *offset = fold_build2 (MULT_EXPR, TREE_TYPE (idx), idx,
+                                array_ref_element_size (op0)); 
        }
       else
        {
@@ -5903,6 +6042,7 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
   tree arg01 = TREE_OPERAND (arg0, 1);
   unsigned HOST_WIDE_INT lpart;
   HOST_WIDE_INT hpart;
+  bool neg_overflow;
   int overflow;
 
   /* We have to do this the hard way to detect unsigned overflow.
@@ -5913,6 +6053,7 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
                         TREE_INT_CST_HIGH (arg1), &lpart, &hpart);
   prod = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart);
   prod = force_fit_type (prod, -1, overflow, false);
+  neg_overflow = false;
 
   if (TYPE_UNSIGNED (TREE_TYPE (arg0)))
     {
@@ -5935,6 +6076,7 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
       switch (tree_int_cst_sgn (arg1))
        {
        case -1:
+         neg_overflow = true;
          lo = int_const_binop (MINUS_EXPR, prod, tmp, 0);
          hi = prod;
          break;
@@ -5972,7 +6114,8 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
          break;
 
        case  1:
-          lo = int_const_binop (PLUS_EXPR, prod, tmp, 0);
+         neg_overflow = true;
+         lo = int_const_binop (PLUS_EXPR, prod, tmp, 0);
          hi = prod;
          break;
 
@@ -6003,22 +6146,34 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
 
     case LT_EXPR:
       if (TREE_OVERFLOW (lo))
-       return omit_one_operand (type, integer_zero_node, arg00);
+       {
+         tmp = neg_overflow ? integer_zero_node : integer_one_node;
+         return omit_one_operand (type, tmp, arg00);
+       }
       return fold_build2 (LT_EXPR, type, arg00, lo);
 
     case LE_EXPR:
       if (TREE_OVERFLOW (hi))
-       return omit_one_operand (type, integer_one_node, arg00);
+       {
+         tmp = neg_overflow ? integer_zero_node : integer_one_node;
+         return omit_one_operand (type, tmp, arg00);
+       }
       return fold_build2 (LE_EXPR, type, arg00, hi);
 
     case GT_EXPR:
       if (TREE_OVERFLOW (hi))
-       return omit_one_operand (type, integer_zero_node, arg00);
+       {
+         tmp = neg_overflow ? integer_one_node : integer_zero_node;
+         return omit_one_operand (type, tmp, arg00);
+       }
       return fold_build2 (GT_EXPR, type, arg00, hi);
 
     case GE_EXPR:
       if (TREE_OVERFLOW (lo))
-       return omit_one_operand (type, integer_one_node, arg00);
+       {
+         tmp = neg_overflow ? integer_one_node : integer_zero_node;
+         return omit_one_operand (type, tmp, arg00);
+       }
       return fold_build2 (GE_EXPR, type, arg00, lo);
 
     default:
@@ -6056,7 +6211,7 @@ fold_single_bit_test_into_sign_test (enum tree_code code, tree arg0, tree arg1,
          tree stype = lang_hooks.types.signed_type (TREE_TYPE (arg00));
          return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
                              result_type, fold_convert (stype, arg00),
-                             fold_convert (stype, integer_zero_node));
+                             build_int_cst (stype, 0));
        }
     }
 
@@ -6242,8 +6397,6 @@ fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
     return NULL_TREE;
 
   arg1_unw = get_unwidened (arg1, shorter_type);
-  if (!arg1_unw)
-    return NULL_TREE;
 
   /* If possible, express the comparison in the shorter mode.  */
   if ((code == EQ_EXPR || code == NE_EXPR
@@ -6256,7 +6409,9 @@ fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
     return fold_build2 (code, type, arg0_unw,
                       fold_convert (shorter_type, arg1_unw));
 
-  if (TREE_CODE (arg1_unw) != INTEGER_CST)
+  if (TREE_CODE (arg1_unw) != INTEGER_CST
+      || TREE_CODE (shorter_type) != INTEGER_TYPE
+      || !int_fits_type_p (arg1_unw, shorter_type))
     return NULL_TREE;
 
   /* If we are comparing with the integer that does not fit into the range
@@ -6460,7 +6615,7 @@ try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
                                                     TREE_OPERAND (pos, 1)),
                                       fold_convert (itype, delta));
 
-  return build1 (ADDR_EXPR, TREE_TYPE (addr), ret);
+  return fold_build1 (ADDR_EXPR, TREE_TYPE (addr), ret);
 }
 
 
@@ -6508,645 +6663,1612 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
   return fold_build2 (GE_EXPR, type, a, y);
 }
 
-/* Fold a unary expression of code CODE and type TYPE with operand
-   OP0.  Return the folded expression if folding is successful.
-   Otherwise, return NULL_TREE.  */
+/* Fold a sum or difference of at least one multiplication.
+   Returns the folded tree or NULL if no simplification could be made.  */
 
-tree
-fold_unary (enum tree_code code, tree type, tree op0)
+static tree
+fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
 {
-  tree tem;
-  tree arg0;
-  enum tree_code_class kind = TREE_CODE_CLASS (code);
+  tree arg00, arg01, arg10, arg11;
+  tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
 
-  gcc_assert (IS_EXPR_CODE_CLASS (kind)
-             && TREE_CODE_LENGTH (code) == 1);
+  /* (A * C) +- (B * C) -> (A+-B) * C.
+     (A * C) +- A -> A * (C+-1).
+     We are most concerned about the case where C is a constant,
+     but other combinations show up during loop reduction.  Since
+     it is not difficult, try all four possibilities.  */
 
-  arg0 = op0;
-  if (arg0)
+  if (TREE_CODE (arg0) == MULT_EXPR)
     {
-      if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
-       {
-         /* Don't use STRIP_NOPS, because signedness of argument type matters.  */
-         STRIP_SIGN_NOPS (arg0);
+      arg00 = TREE_OPERAND (arg0, 0);
+      arg01 = TREE_OPERAND (arg0, 1);
+    }
+  else
+    {
+      arg00 = arg0;
+      if (!FLOAT_TYPE_P (type))
+       arg01 = build_int_cst (type, 1);
+      else
+       arg01 = build_real (type, dconst1);
+    }
+  if (TREE_CODE (arg1) == MULT_EXPR)
+    {
+      arg10 = TREE_OPERAND (arg1, 0);
+      arg11 = TREE_OPERAND (arg1, 1);
+    }
+  else
+    {
+      arg10 = arg1;
+      if (!FLOAT_TYPE_P (type))
+       arg11 = build_int_cst (type, 1);
+      else
+       arg11 = build_real (type, dconst1);
+    }
+  same = NULL_TREE;
+
+  if (operand_equal_p (arg01, arg11, 0))
+    same = arg01, alt0 = arg00, alt1 = arg10;
+  else if (operand_equal_p (arg00, arg10, 0))
+    same = arg00, alt0 = arg01, alt1 = arg11;
+  else if (operand_equal_p (arg00, arg11, 0))
+    same = arg00, alt0 = arg01, alt1 = arg10;
+  else if (operand_equal_p (arg01, arg10, 0))
+    same = arg01, alt0 = arg00, alt1 = arg11;
+
+  /* No identical multiplicands; see if we can find a common
+     power-of-two factor in non-power-of-two multiplies.  This
+     can help in multi-dimensional array access.  */
+  else if (host_integerp (arg01, 0)
+          && host_integerp (arg11, 0))
+    {
+      HOST_WIDE_INT int01, int11, tmp;
+      bool swap = false;
+      tree maybe_same;
+      int01 = TREE_INT_CST_LOW (arg01);
+      int11 = TREE_INT_CST_LOW (arg11);
+
+      /* Move min of absolute values to int11.  */
+      if ((int01 >= 0 ? int01 : -int01)
+         < (int11 >= 0 ? int11 : -int11))
+        {
+         tmp = int01, int01 = int11, int11 = tmp;
+         alt0 = arg00, arg00 = arg10, arg10 = alt0;
+         maybe_same = arg01;
+         swap = true;
        }
       else
-       {
-         /* Strip any conversions that don't change the mode.  This
-            is safe for every expression, except for a comparison
-            expression because its signedness is derived from its
-            operands.
+       maybe_same = arg11;
 
-            Note that this is done as an internal manipulation within
-            the constant folder, in order to find the simplest
-            representation of the arguments so that their form can be
-            studied.  In any cases, the appropriate type conversions
-            should be put back in the tree that will get out of the
-            constant folder.  */
-         STRIP_NOPS (arg0);
+      if (exact_log2 (int11) > 0 && int01 % int11 == 0)
+        {
+         alt0 = fold_build2 (MULT_EXPR, TREE_TYPE (arg00), arg00,
+                             build_int_cst (TREE_TYPE (arg00),
+                                            int01 / int11));
+         alt1 = arg10;
+         same = maybe_same;
+         if (swap)
+           maybe_same = alt0, alt0 = alt1, alt1 = maybe_same;
        }
     }
 
-  if (TREE_CODE_CLASS (code) == tcc_unary)
-    {
-      if (TREE_CODE (arg0) == COMPOUND_EXPR)
-       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                      fold_build1 (code, type, TREE_OPERAND (arg0, 1)));
-      else if (TREE_CODE (arg0) == COND_EXPR)
-       {
-         tree arg01 = TREE_OPERAND (arg0, 1);
-         tree arg02 = TREE_OPERAND (arg0, 2);
-         if (! VOID_TYPE_P (TREE_TYPE (arg01)))
-           arg01 = fold_build1 (code, type, arg01);
-         if (! VOID_TYPE_P (TREE_TYPE (arg02)))
-           arg02 = fold_build1 (code, type, arg02);
-         tem = fold_build3 (COND_EXPR, type, TREE_OPERAND (arg0, 0),
-                            arg01, arg02);
+  if (same)
+    return fold_build2 (MULT_EXPR, type,
+                       fold_build2 (code, type,
+                                    fold_convert (type, alt0),
+                                    fold_convert (type, alt1)),
+                       fold_convert (type, same));
 
-         /* If this was a conversion, and all we did was to move into
-            inside the COND_EXPR, bring it back out.  But leave it if
-            it is a conversion from integer to integer and the
-            result precision is no wider than a word since such a
-            conversion is cheap and may be optimized away by combine,
-            while it couldn't if it were outside the COND_EXPR.  Then return
-            so we don't get into an infinite recursion loop taking the
-            conversion out and then back in.  */
+  return NULL_TREE;
+}
 
-         if ((code == NOP_EXPR || code == CONVERT_EXPR
-              || code == NON_LVALUE_EXPR)
-             && TREE_CODE (tem) == COND_EXPR
-             && TREE_CODE (TREE_OPERAND (tem, 1)) == code
-             && TREE_CODE (TREE_OPERAND (tem, 2)) == code
-             && ! VOID_TYPE_P (TREE_OPERAND (tem, 1))
-             && ! VOID_TYPE_P (TREE_OPERAND (tem, 2))
-             && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))
-                 == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0)))
-             && (! (INTEGRAL_TYPE_P (TREE_TYPE (tem))
-                    && (INTEGRAL_TYPE_P
-                        (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))))
-                    && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD)
-                 || flag_syntax_only))
-           tem = build1 (code, type,
-                         build3 (COND_EXPR,
-                                 TREE_TYPE (TREE_OPERAND
-                                            (TREE_OPERAND (tem, 1), 0)),
-                                 TREE_OPERAND (tem, 0),
-                                 TREE_OPERAND (TREE_OPERAND (tem, 1), 0),
-                                 TREE_OPERAND (TREE_OPERAND (tem, 2), 0)));
-         return tem;
-       }
-      else if (COMPARISON_CLASS_P (arg0))
+/* Subroutine of native_encode_expr.  Encode the INTEGER_CST
+   specified by EXPR into the buffer PTR of length LEN bytes.
+   Return the number of bytes placed in the buffer, or zero
+   upon failure.  */
+
+static int
+native_encode_int (tree expr, unsigned char *ptr, int len)
+{
+  tree type = TREE_TYPE (expr);
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  int byte, offset, word, words;
+  unsigned char value;
+
+  if (total_bytes > len)
+    return 0;
+  words = total_bytes / UNITS_PER_WORD;
+
+  for (byte = 0; byte < total_bytes; byte++)
+    {
+      int bitpos = byte * BITS_PER_UNIT;
+      if (bitpos < HOST_BITS_PER_WIDE_INT)
+       value = (unsigned char) (TREE_INT_CST_LOW (expr) >> bitpos);
+      else
+       value = (unsigned char) (TREE_INT_CST_HIGH (expr)
+                                >> (bitpos - HOST_BITS_PER_WIDE_INT));
+
+      if (total_bytes > UNITS_PER_WORD)
        {
-         if (TREE_CODE (type) == BOOLEAN_TYPE)
-           {
-             arg0 = copy_node (arg0);
-             TREE_TYPE (arg0) = type;
-             return arg0;
-           }
-         else if (TREE_CODE (type) != INTEGER_TYPE)
-           return fold_build3 (COND_EXPR, type, arg0,
-                               fold_build1 (code, type,
-                                            integer_one_node),
-                               fold_build1 (code, type,
-                                            integer_zero_node));
+         word = byte / UNITS_PER_WORD;
+         if (WORDS_BIG_ENDIAN)
+           word = (words - 1) - word;
+         offset = word * UNITS_PER_WORD;
+         if (BYTES_BIG_ENDIAN)
+           offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+         else
+           offset += byte % UNITS_PER_WORD;
        }
-   }
+      else
+       offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
+      ptr[offset] = value;
+    }
+  return total_bytes;
+}
 
-  switch (code)
+
+/* Subroutine of native_encode_expr.  Encode the REAL_CST
+   specified by EXPR into the buffer PTR of length LEN bytes.
+   Return the number of bytes placed in the buffer, or zero
+   upon failure.  */
+
+static int
+native_encode_real (tree expr, unsigned char *ptr, int len)
+{
+  tree type = TREE_TYPE (expr);
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  int byte, offset, word, words;
+  unsigned char value;
+
+  /* There are always 32 bits in each long, no matter the size of
+     the hosts long.  We handle floating point representations with
+     up to 192 bits.  */
+  long tmp[6];
+
+  if (total_bytes > len)
+    return 0;
+  words = total_bytes / UNITS_PER_WORD;
+
+  real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
+
+  for (byte = 0; byte < total_bytes; byte++)
     {
-    case NOP_EXPR:
-    case FLOAT_EXPR:
-    case CONVERT_EXPR:
-    case FIX_TRUNC_EXPR:
-    case FIX_CEIL_EXPR:
-    case FIX_FLOOR_EXPR:
-    case FIX_ROUND_EXPR:
-      if (TREE_TYPE (op0) == type)
-       return op0;
+      int bitpos = byte * BITS_PER_UNIT;
+      value = (unsigned char) (tmp[bitpos / 32] >> (bitpos & 31));
 
-      /* Handle cases of two conversions in a row.  */
-      if (TREE_CODE (op0) == NOP_EXPR
-         || TREE_CODE (op0) == CONVERT_EXPR)
+      if (total_bytes > UNITS_PER_WORD)
        {
-         tree inside_type = TREE_TYPE (TREE_OPERAND (op0, 0));
-         tree inter_type = TREE_TYPE (op0);
-         int inside_int = INTEGRAL_TYPE_P (inside_type);
-         int inside_ptr = POINTER_TYPE_P (inside_type);
-         int inside_float = FLOAT_TYPE_P (inside_type);
-         int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
-         unsigned int inside_prec = TYPE_PRECISION (inside_type);
-         int inside_unsignedp = TYPE_UNSIGNED (inside_type);
-         int inter_int = INTEGRAL_TYPE_P (inter_type);
-         int inter_ptr = POINTER_TYPE_P (inter_type);
-         int inter_float = FLOAT_TYPE_P (inter_type);
-         int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
-         unsigned int inter_prec = TYPE_PRECISION (inter_type);
-         int inter_unsignedp = TYPE_UNSIGNED (inter_type);
-         int final_int = INTEGRAL_TYPE_P (type);
-         int final_ptr = POINTER_TYPE_P (type);
-         int final_float = FLOAT_TYPE_P (type);
-         int final_vec = TREE_CODE (type) == VECTOR_TYPE;
-         unsigned int final_prec = TYPE_PRECISION (type);
-         int final_unsignedp = TYPE_UNSIGNED (type);
+         word = byte / UNITS_PER_WORD;
+         if (FLOAT_WORDS_BIG_ENDIAN)
+           word = (words - 1) - word;
+         offset = word * UNITS_PER_WORD;
+         if (BYTES_BIG_ENDIAN)
+           offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+         else
+           offset += byte % UNITS_PER_WORD;
+       }
+      else
+       offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
+      ptr[offset] = value;
+    }
+  return total_bytes;
+}
 
-         /* In addition to the cases of two conversions in a row
-            handled below, if we are converting something to its own
-            type via an object of identical or wider precision, neither
-            conversion is needed.  */
-         if (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (type)
-             && ((inter_int && final_int) || (inter_float && final_float))
-             && inter_prec >= final_prec)
-           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
+/* Subroutine of native_encode_expr.  Encode the COMPLEX_CST
+   specified by EXPR into the buffer PTR of length LEN bytes.
+   Return the number of bytes placed in the buffer, or zero
+   upon failure.  */
 
-         /* Likewise, if the intermediate and final types are either both
-            float or both integer, we don't need the middle conversion if
-            it is wider than the final type and doesn't change the signedness
-            (for integers).  Avoid this if the final type is a pointer
-            since then we sometimes need the inner conversion.  Likewise if
-            the outer has a precision not equal to the size of its mode.  */
-         if ((((inter_int || inter_ptr) && (inside_int || inside_ptr))
-              || (inter_float && inside_float)
-              || (inter_vec && inside_vec))
-             && inter_prec >= inside_prec
-             && (inter_float || inter_vec
-                 || inter_unsignedp == inside_unsignedp)
-             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
-                   && TYPE_MODE (type) == TYPE_MODE (inter_type))
-             && ! final_ptr
-             && (! final_vec || inter_prec == inside_prec))
-           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
+static int
+native_encode_complex (tree expr, unsigned char *ptr, int len)
+{
+  int rsize, isize;
+  tree part;
 
-         /* If we have a sign-extension of a zero-extended value, we can
-            replace that by a single zero-extension.  */
-         if (inside_int && inter_int && final_int
-             && inside_prec < inter_prec && inter_prec < final_prec
-             && inside_unsignedp && !inter_unsignedp)
-           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
+  part = TREE_REALPART (expr);
+  rsize = native_encode_expr (part, ptr, len);
+  if (rsize == 0)
+    return 0;
+  part = TREE_IMAGPART (expr);
+  isize = native_encode_expr (part, ptr+rsize, len-rsize);
+  if (isize != rsize)
+    return 0;
+  return rsize + isize;
+}
 
-         /* Two conversions in a row are not needed unless:
-            - some conversion is floating-point (overstrict for now), or
-            - some conversion is a vector (overstrict for now), or
-            - the intermediate type is narrower than both initial and
-              final, or
-            - the intermediate type and innermost type differ in signedness,
-              and the outermost type is wider than the intermediate, or
-            - the initial type is a pointer type and the precisions of the
-              intermediate and final types differ, or
-            - the final type is a pointer type and the precisions of the
-              initial and intermediate types differ.  */
-         if (! inside_float && ! inter_float && ! final_float
-             && ! inside_vec && ! inter_vec && ! final_vec
-             && (inter_prec > inside_prec || inter_prec > final_prec)
-             && ! (inside_int && inter_int
-                   && inter_unsignedp != inside_unsignedp
-                   && inter_prec < final_prec)
-             && ((inter_unsignedp && inter_prec > inside_prec)
-                 == (final_unsignedp && final_prec > inter_prec))
-             && ! (inside_ptr && inter_prec != final_prec)
-             && ! (final_ptr && inside_prec != inter_prec)
-             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
-                   && TYPE_MODE (type) == TYPE_MODE (inter_type))
-             && ! final_ptr)
-           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
-       }
 
-      if (TREE_CODE (op0) == MODIFY_EXPR
-         && TREE_CONSTANT (TREE_OPERAND (op0, 1))
-         /* Detect assigning a bitfield.  */
-         && !(TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF
-              && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (op0, 0), 1))))
+/* Subroutine of native_encode_expr.  Encode the VECTOR_CST
+   specified by EXPR into the buffer PTR of length LEN bytes.
+   Return the number of bytes placed in the buffer, or zero
+   upon failure.  */
+
+static int
+native_encode_vector (tree expr, unsigned char *ptr, int len)
+{
+  int i, size, offset, count;
+  tree elem, elements;
+
+  size = 0;
+  offset = 0;
+  elements = TREE_VECTOR_CST_ELTS (expr);
+  count = TYPE_VECTOR_SUBPARTS (TREE_TYPE (expr));
+  for (i = 0; i < count; i++)
+    {
+      if (elements)
        {
-         /* Don't leave an assignment inside a conversion
-            unless assigning a bitfield.  */
-         tem = fold_build1 (code, type, TREE_OPERAND (op0, 1));
-         /* First do the assignment, then return converted constant.  */
-         tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, tem);
-         TREE_NO_WARNING (tem) = 1;
-         TREE_USED (tem) = 1;
-         return tem;
+         elem = TREE_VALUE (elements);
+         elements = TREE_CHAIN (elements);
        }
+      else
+       elem = NULL_TREE;
 
-      /* Convert (T)(x & c) into (T)x & (T)c, if c is an integer
-        constants (if x has signed type, the sign bit cannot be set
-        in c).  This folds extension into the BIT_AND_EXPR.  */
-      if (INTEGRAL_TYPE_P (type)
-         && TREE_CODE (type) != BOOLEAN_TYPE
-         && TREE_CODE (op0) == BIT_AND_EXPR
-         && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST)
+      if (elem)
        {
-         tree and = op0;
-         tree and0 = TREE_OPERAND (and, 0), and1 = TREE_OPERAND (and, 1);
-         int change = 0;
+         size = native_encode_expr (elem, ptr+offset, len-offset);
+         if (size == 0)
+           return 0;
+       }
+      else if (size != 0)
+       {
+         if (offset + size > len)
+           return 0;
+         memset (ptr+offset, 0, size);
+       }
+      else
+       return 0;
+      offset += size;
+    }
+  return offset;
+}
 
-         if (TYPE_UNSIGNED (TREE_TYPE (and))
-             || (TYPE_PRECISION (type)
-                 <= TYPE_PRECISION (TREE_TYPE (and))))
-           change = 1;
-         else if (TYPE_PRECISION (TREE_TYPE (and1))
-                  <= HOST_BITS_PER_WIDE_INT
-                  && host_integerp (and1, 1))
-           {
-             unsigned HOST_WIDE_INT cst;
 
-             cst = tree_low_cst (and1, 1);
-             cst &= (HOST_WIDE_INT) -1
-                    << (TYPE_PRECISION (TREE_TYPE (and1)) - 1);
-             change = (cst == 0);
-#ifdef LOAD_EXTEND_OP
-             if (change
-                 && !flag_syntax_only
-                 && (LOAD_EXTEND_OP (TYPE_MODE (TREE_TYPE (and0)))
-                     == ZERO_EXTEND))
-               {
-                 tree uns = lang_hooks.types.unsigned_type (TREE_TYPE (and0));
-                 and0 = fold_convert (uns, and0);
-                 and1 = fold_convert (uns, and1);
-               }
-#endif
-           }
-         if (change)
-           {
-             tem = build_int_cst_wide (type, TREE_INT_CST_LOW (and1),
-                                       TREE_INT_CST_HIGH (and1));
-             tem = force_fit_type (tem, 0, TREE_OVERFLOW (and1),
-                                   TREE_CONSTANT_OVERFLOW (and1));
-             return fold_build2 (BIT_AND_EXPR, type,
-                                 fold_convert (type, and0), tem);
-           }
-       }
+/* Subroutine of fold_view_convert_expr.  Encode the INTEGER_CST,
+   REAL_CST, COMPLEX_CST or VECTOR_CST specified by EXPR into the
+   buffer PTR of length LEN bytes.  Return the number of bytes
+   placed in the buffer, or zero upon failure.  */
 
-      /* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and
-        T2 being pointers to types of the same size.  */
-      if (POINTER_TYPE_P (type)
-         && BINARY_CLASS_P (arg0)
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
-         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0))))
-       {
-         tree arg00 = TREE_OPERAND (arg0, 0);
-         tree t0 = type;
-         tree t1 = TREE_TYPE (arg00);
-         tree tt0 = TREE_TYPE (t0);
-         tree tt1 = TREE_TYPE (t1);
-         tree s0 = TYPE_SIZE (tt0);
-         tree s1 = TYPE_SIZE (tt1);
+static int
+native_encode_expr (tree expr, unsigned char *ptr, int len)
+{
+  switch (TREE_CODE (expr))
+    {
+    case INTEGER_CST:
+      return native_encode_int (expr, ptr, len);
 
-         if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST))
-           return build2 (TREE_CODE (arg0), t0, fold_convert (t0, arg00),
-                          TREE_OPERAND (arg0, 1));
-       }
+    case REAL_CST:
+      return native_encode_real (expr, ptr, len);
 
-      tem = fold_convert_const (code, type, arg0);
-      return tem ? tem : NULL_TREE;
+    case COMPLEX_CST:
+      return native_encode_complex (expr, ptr, len);
 
-    case VIEW_CONVERT_EXPR:
-      if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
-       return build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
-      return NULL_TREE;
+    case VECTOR_CST:
+      return native_encode_vector (expr, ptr, len);
 
-    case NEGATE_EXPR:
-      if (negate_expr_p (arg0))
-       return fold_convert (type, negate_expr (arg0));
-      /* Convert - (~A) to A + 1.  */
-      if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == BIT_NOT_EXPR)
-       return fold_build2 (PLUS_EXPR, type, TREE_OPERAND (arg0, 0),
-                           build_int_cst (type, 1));
-      return NULL_TREE;
+    default:
+      return 0;
+    }
+}
 
-    case ABS_EXPR:
-      if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST)
-       return fold_abs_const (arg0, type);
-      else if (TREE_CODE (arg0) == NEGATE_EXPR)
-       return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
-      /* Convert fabs((double)float) into (double)fabsf(float).  */
-      else if (TREE_CODE (arg0) == NOP_EXPR
-              && TREE_CODE (type) == REAL_TYPE)
+
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as an INTEGER_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
+
+static tree
+native_interpret_int (tree type, unsigned char *ptr, int len)
+{
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  int byte, offset, word, words;
+  unsigned char value;
+  unsigned int HOST_WIDE_INT lo = 0;
+  HOST_WIDE_INT hi = 0;
+
+  if (total_bytes > len)
+    return NULL_TREE;
+  if (total_bytes * BITS_PER_UNIT > 2 * HOST_BITS_PER_WIDE_INT)
+    return NULL_TREE;
+  words = total_bytes / UNITS_PER_WORD;
+
+  for (byte = 0; byte < total_bytes; byte++)
+    {
+      int bitpos = byte * BITS_PER_UNIT;
+      if (total_bytes > UNITS_PER_WORD)
        {
-         tree targ0 = strip_float_extensions (arg0);
-         if (targ0 != arg0)
-           return fold_convert (type, fold_build1 (ABS_EXPR,
-                                                   TREE_TYPE (targ0),
-                                                   targ0));
+         word = byte / UNITS_PER_WORD;
+         if (WORDS_BIG_ENDIAN)
+           word = (words - 1) - word;
+         offset = word * UNITS_PER_WORD;
+         if (BYTES_BIG_ENDIAN)
+           offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+         else
+           offset += byte % UNITS_PER_WORD;
        }
-      else if (tree_expr_nonnegative_p (arg0))
-       return arg0;
+      else
+       offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
+      value = ptr[offset];
 
-      /* Strip sign ops from argument.  */
-      if (TREE_CODE (type) == REAL_TYPE)
+      if (bitpos < HOST_BITS_PER_WIDE_INT)
+       lo |= (unsigned HOST_WIDE_INT) value << bitpos;
+      else
+       hi |= (unsigned HOST_WIDE_INT) value
+             << (bitpos - HOST_BITS_PER_WIDE_INT);
+    }
+
+  return force_fit_type (build_int_cst_wide (type, lo, hi),
+                        0, false, false);
+}
+
+
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a REAL_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
+
+static tree
+native_interpret_real (tree type, unsigned char *ptr, int len)
+{
+  enum machine_mode mode = TYPE_MODE (type);
+  int total_bytes = GET_MODE_SIZE (mode);
+  int byte, offset, word, words;
+  unsigned char value;
+  /* There are always 32 bits in each long, no matter the size of
+     the hosts long.  We handle floating point representations with
+     up to 192 bits.  */
+  REAL_VALUE_TYPE r;
+  long tmp[6];
+
+  total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  if (total_bytes > len || total_bytes > 24)
+    return NULL_TREE;
+  words = total_bytes / UNITS_PER_WORD;
+
+  memset (tmp, 0, sizeof (tmp));
+  for (byte = 0; byte < total_bytes; byte++)
+    {
+      int bitpos = byte * BITS_PER_UNIT;
+      if (total_bytes > UNITS_PER_WORD)
        {
-         tem = fold_strip_sign_ops (arg0);
-         if (tem)
-           return fold_build1 (ABS_EXPR, type, fold_convert (type, tem));
+         word = byte / UNITS_PER_WORD;
+         if (FLOAT_WORDS_BIG_ENDIAN)
+           word = (words - 1) - word;
+         offset = word * UNITS_PER_WORD;
+         if (BYTES_BIG_ENDIAN)
+           offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+         else
+           offset += byte % UNITS_PER_WORD;
        }
-      return NULL_TREE;
+      else
+       offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
+      value = ptr[offset];
 
-    case CONJ_EXPR:
-      if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
-       return fold_convert (type, arg0);
-      else if (TREE_CODE (arg0) == COMPLEX_EXPR)
-       return build2 (COMPLEX_EXPR, type,
-                      TREE_OPERAND (arg0, 0),
-                      negate_expr (TREE_OPERAND (arg0, 1)));
-      else if (TREE_CODE (arg0) == COMPLEX_CST)
-       return build_complex (type, TREE_REALPART (arg0),
-                             negate_expr (TREE_IMAGPART (arg0)));
-      else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-       return fold_build2 (TREE_CODE (arg0), type,
-                           fold_build1 (CONJ_EXPR, type,
-                                        TREE_OPERAND (arg0, 0)),
-                           fold_build1 (CONJ_EXPR, type,
-                                        TREE_OPERAND (arg0, 1)));
-      else if (TREE_CODE (arg0) == CONJ_EXPR)
-       return TREE_OPERAND (arg0, 0);
-      return NULL_TREE;
-
-    case BIT_NOT_EXPR:
-      if (TREE_CODE (arg0) == INTEGER_CST)
-        return fold_not_const (arg0, type);
-      else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
-       return TREE_OPERAND (arg0, 0);
-      /* Convert ~ (-A) to A - 1.  */
-      else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
-       return fold_build2 (MINUS_EXPR, type, TREE_OPERAND (arg0, 0),
-                           build_int_cst (type, 1));
-      /* Convert ~ (A - 1) or ~ (A + -1) to -A.  */
-      else if (INTEGRAL_TYPE_P (type)
-              && ((TREE_CODE (arg0) == MINUS_EXPR
-                   && integer_onep (TREE_OPERAND (arg0, 1)))
-                  || (TREE_CODE (arg0) == PLUS_EXPR
-                      && integer_all_onesp (TREE_OPERAND (arg0, 1)))))
-       return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
-      /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify.  */
-      else if (TREE_CODE (arg0) == BIT_XOR_EXPR
-              && (tem = fold_unary (BIT_NOT_EXPR, type,
-                                    fold_convert (type,
-                                                  TREE_OPERAND (arg0, 0)))))
-       return fold_build2 (BIT_XOR_EXPR, type, tem,
-                           fold_convert (type, TREE_OPERAND (arg0, 1)));
-      else if (TREE_CODE (arg0) == BIT_XOR_EXPR
-              && (tem = fold_unary (BIT_NOT_EXPR, type,
-                                    fold_convert (type,
-                                                  TREE_OPERAND (arg0, 1)))))
-       return fold_build2 (BIT_XOR_EXPR, type,
-                           fold_convert (type, TREE_OPERAND (arg0, 0)), tem);
-
-      return NULL_TREE;
+      tmp[bitpos / 32] |= (unsigned long)value << (bitpos & 31);
+    }
 
-    case TRUTH_NOT_EXPR:
-      /* The argument to invert_truthvalue must have Boolean type.  */
-      if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
-          arg0 = fold_convert (boolean_type_node, arg0);
+  real_from_target (&r, tmp, mode);
+  return build_real (type, r);
+}
 
-      /* Note that the operand of this must be an int
-        and its values must be 0 or 1.
-        ("true" is a fixed value perhaps depending on the language,
-        but we don't handle values other than 1 correctly yet.)  */
-      tem = invert_truthvalue (arg0);
-      /* Avoid infinite recursion.  */
-      if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
-       return NULL_TREE;
-      return fold_convert (type, tem);
 
-    case REALPART_EXPR:
-      if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
-       return NULL_TREE;
-      else if (TREE_CODE (arg0) == COMPLEX_EXPR)
-       return omit_one_operand (type, TREE_OPERAND (arg0, 0),
-                                TREE_OPERAND (arg0, 1));
-      else if (TREE_CODE (arg0) == COMPLEX_CST)
-       return TREE_REALPART (arg0);
-      else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-       return fold_build2 (TREE_CODE (arg0), type,
-                           fold_build1 (REALPART_EXPR, type,
-                                        TREE_OPERAND (arg0, 0)),
-                           fold_build1 (REALPART_EXPR, type,
-                                        TREE_OPERAND (arg0, 1)));
-      return NULL_TREE;
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a COMPLEX_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
 
-    case IMAGPART_EXPR:
-      if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
-       return fold_convert (type, integer_zero_node);
-      else if (TREE_CODE (arg0) == COMPLEX_EXPR)
-       return omit_one_operand (type, TREE_OPERAND (arg0, 1),
-                                TREE_OPERAND (arg0, 0));
-      else if (TREE_CODE (arg0) == COMPLEX_CST)
-       return TREE_IMAGPART (arg0);
-      else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-       return fold_build2 (TREE_CODE (arg0), type,
-                           fold_build1 (IMAGPART_EXPR, type,
-                                        TREE_OPERAND (arg0, 0)),
-                           fold_build1 (IMAGPART_EXPR, type,
-                                        TREE_OPERAND (arg0, 1)));
-      return NULL_TREE;
+static tree
+native_interpret_complex (tree type, unsigned char *ptr, int len)
+{
+  tree etype, rpart, ipart;
+  int size;
 
-    default:
-      return NULL_TREE;
-    } /* switch (code) */
+  etype = TREE_TYPE (type);
+  size = GET_MODE_SIZE (TYPE_MODE (etype));
+  if (size * 2 > len)
+    return NULL_TREE;
+  rpart = native_interpret_expr (etype, ptr, size);
+  if (!rpart)
+    return NULL_TREE;
+  ipart = native_interpret_expr (etype, ptr+size, size);
+  if (!ipart)
+    return NULL_TREE;
+  return build_complex (type, rpart, ipart);
 }
 
-/* Fold a binary expression of code CODE and type TYPE with operands
-   OP0 and OP1.  Return the folded expression if folding is
-   successful.  Otherwise, return NULL_TREE.  */
-
-tree
-fold_binary (enum tree_code code, tree type, tree op0, tree op1)
-{
-  tree t1 = NULL_TREE;
-  tree tem;
-  tree arg0 = NULL_TREE, arg1 = NULL_TREE;
-  enum tree_code_class kind = TREE_CODE_CLASS (code);
 
-  /* WINS will be nonzero when the switch is done
-     if all operands are constant.  */
-  int wins = 1;
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a VECTOR_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
 
-  gcc_assert (IS_EXPR_CODE_CLASS (kind)
-             && TREE_CODE_LENGTH (code) == 2);
+static tree
+native_interpret_vector (tree type, unsigned char *ptr, int len)
+{
+  tree etype, elem, elements;
+  int i, size, count;
 
-  arg0 = op0;
-  arg1 = op1;
+  etype = TREE_TYPE (type);
+  size = GET_MODE_SIZE (TYPE_MODE (etype));
+  count = TYPE_VECTOR_SUBPARTS (type);
+  if (size * count > len)
+    return NULL_TREE;
 
-  if (arg0)
+  elements = NULL_TREE;
+  for (i = count - 1; i >= 0; i--)
     {
-      tree subop;
-
-      /* Strip any conversions that don't change the mode.  This is
-        safe for every expression, except for a comparison expression
-        because its signedness is derived from its operands.  So, in
-        the latter case, only strip conversions that don't change the
-        signedness.
-
-        Note that this is done as an internal manipulation within the
-        constant folder, in order to find the simplest representation
-        of the arguments so that their form can be studied.  In any
-        cases, the appropriate type conversions should be put back in
-        the tree that will get out of the constant folder.  */
-      if (kind == tcc_comparison)
-       STRIP_SIGN_NOPS (arg0);
-      else
-       STRIP_NOPS (arg0);
+      elem = native_interpret_expr (etype, ptr+(i*size), size);
+      if (!elem)
+       return NULL_TREE;
+      elements = tree_cons (NULL_TREE, elem, elements);
+    }
+  return build_vector (type, elements);
+}
 
-      if (TREE_CODE (arg0) == COMPLEX_CST)
-       subop = TREE_REALPART (arg0);
-      else
-       subop = arg0;
 
-      if (TREE_CODE (subop) != INTEGER_CST
-         && TREE_CODE (subop) != REAL_CST)
-       /* Note that TREE_CONSTANT isn't enough:
-          static var addresses are constant but we can't
-          do arithmetic on them.  */
-       wins = 0;
-    }
+/* Subroutine of fold_view_convert_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a constant of type TYPE.  For
+   INTEGRAL_TYPE_P we return an INTEGER_CST, for SCALAR_FLOAT_TYPE_P
+   we return a REAL_CST, etc...  If the buffer cannot be interpreted,
+   return NULL_TREE.  */
 
-  if (arg1)
+static tree
+native_interpret_expr (tree type, unsigned char *ptr, int len)
+{
+  switch (TREE_CODE (type))
     {
-      tree subop;
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+      return native_interpret_int (type, ptr, len);
 
-      /* Strip any conversions that don't change the mode.  This is
-        safe for every expression, except for a comparison expression
-        because its signedness is derived from its operands.  So, in
-        the latter case, only strip conversions that don't change the
-        signedness.
+    case REAL_TYPE:
+      return native_interpret_real (type, ptr, len);
 
-        Note that this is done as an internal manipulation within the
-        constant folder, in order to find the simplest representation
-        of the arguments so that their form can be studied.  In any
-        cases, the appropriate type conversions should be put back in
-        the tree that will get out of the constant folder.  */
-      if (kind == tcc_comparison)
-       STRIP_SIGN_NOPS (arg1);
-      else
-       STRIP_NOPS (arg1);
+    case COMPLEX_TYPE:
+      return native_interpret_complex (type, ptr, len);
 
-      if (TREE_CODE (arg1) == COMPLEX_CST)
-       subop = TREE_REALPART (arg1);
-      else
-       subop = arg1;
+    case VECTOR_TYPE:
+      return native_interpret_vector (type, ptr, len);
 
-      if (TREE_CODE (subop) != INTEGER_CST
-         && TREE_CODE (subop) != REAL_CST)
-       /* Note that TREE_CONSTANT isn't enough:
-          static var addresses are constant but we can't
-          do arithmetic on them.  */
-       wins = 0;
+    default:
+      return NULL_TREE;
     }
+}
 
-  /* If this is a commutative operation, and ARG0 is a constant, move it
-     to ARG1 to reduce the number of tests below.  */
-  if (commutative_tree_code (code)
-      && tree_swap_operands_p (arg0, arg1, true))
-    return fold_build2 (code, type, op1, op0);
 
-  /* Now WINS is set as described above,
-     ARG0 is the first operand of EXPR,
-     and ARG1 is the second operand (if it has more than one operand).
+/* Fold a VIEW_CONVERT_EXPR of a constant expression EXPR to type
+   TYPE at compile-time.  If we're unable to perform the conversion
+   return NULL_TREE.  */
 
-     First check for cases where an arithmetic operation is applied to a
-     compound, conditional, or comparison operation.  Push the arithmetic
-     operation inside the compound or conditional to see if any folding
-     can then be done.  Convert comparison to conditional for this purpose.
-     The also optimizes non-constant cases that used to be done in
-     expand_expr.
+static tree
+fold_view_convert_expr (tree type, tree expr)
+{
+  /* We support up to 512-bit values (for V8DFmode).  */
+  unsigned char buffer[64];
+  int len;
 
-     Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR,
-     one of the operands is a comparison and the other is a comparison, a
-     BIT_AND_EXPR with the constant 1, or a truth value.  In that case, the
-     code below would make the expression more complex.  Change it to a
-     TRUTH_{AND,OR}_EXPR.  Likewise, convert a similar NE_EXPR to
-     TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR.  */
+  /* Check that the host and target are sane.  */
+  if (CHAR_BIT != 8 || BITS_PER_UNIT != 8)
+    return NULL_TREE;
 
-  if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR
-       || code == EQ_EXPR || code == NE_EXPR)
-      && ((truth_value_p (TREE_CODE (arg0))
-          && (truth_value_p (TREE_CODE (arg1))
-              || (TREE_CODE (arg1) == BIT_AND_EXPR
-                  && integer_onep (TREE_OPERAND (arg1, 1)))))
-         || (truth_value_p (TREE_CODE (arg1))
-             && (truth_value_p (TREE_CODE (arg0))
-                 || (TREE_CODE (arg0) == BIT_AND_EXPR
-                     && integer_onep (TREE_OPERAND (arg0, 1)))))))
-    {
-      tem = fold_build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
-                        : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
-                        : TRUTH_XOR_EXPR,
-                        boolean_type_node,
-                        fold_convert (boolean_type_node, arg0),
-                        fold_convert (boolean_type_node, arg1));
+  len = native_encode_expr (expr, buffer, sizeof (buffer));
+  if (len == 0)
+    return NULL_TREE;
 
-      if (code == EQ_EXPR)
-       tem = invert_truthvalue (tem);
+  return native_interpret_expr (type, buffer, len);
+}
 
-      return fold_convert (type, tem);
-    }
 
-  if (TREE_CODE_CLASS (code) == tcc_comparison
-          && TREE_CODE (arg0) == COMPOUND_EXPR)
-    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                  fold_build2 (code, type, TREE_OPERAND (arg0, 1), arg1));
-  else if (TREE_CODE_CLASS (code) == tcc_comparison
-          && TREE_CODE (arg1) == COMPOUND_EXPR)
-    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
-                  fold_build2 (code, type, arg0, TREE_OPERAND (arg1, 1)));
-  else if (TREE_CODE_CLASS (code) == tcc_binary
-          || TREE_CODE_CLASS (code) == tcc_comparison)
-    {
-      if (TREE_CODE (arg0) == COMPOUND_EXPR)
-       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                      fold_build2 (code, type, TREE_OPERAND (arg0, 1),
-                                   arg1));
-      if (TREE_CODE (arg1) == COMPOUND_EXPR
-         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
-       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
-                      fold_build2 (code, type,
-                                   arg0, TREE_OPERAND (arg1, 1)));
+/* Fold a unary expression of code CODE and type TYPE with operand
+   OP0.  Return the folded expression if folding is successful.
+   Otherwise, return NULL_TREE.  */
 
-      if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
+tree
+fold_unary (enum tree_code code, tree type, tree op0)
+{
+  tree tem;
+  tree arg0;
+  enum tree_code_class kind = TREE_CODE_CLASS (code);
+
+  gcc_assert (IS_EXPR_CODE_CLASS (kind)
+             && TREE_CODE_LENGTH (code) == 1);
+
+  arg0 = op0;
+  if (arg0)
+    {
+      if (code == NOP_EXPR || code == CONVERT_EXPR
+         || code == FLOAT_EXPR || code == ABS_EXPR)
        {
-         tem = fold_binary_op_with_conditional_arg (code, type, op0, op1,
-                                                    arg0, arg1, 
-                                                    /*cond_first_p=*/1);
-         if (tem != NULL_TREE)
-           return tem;
+         /* Don't use STRIP_NOPS, because signedness of argument type
+            matters.  */
+         STRIP_SIGN_NOPS (arg0);
        }
-
-      if (TREE_CODE (arg1) == COND_EXPR || COMPARISON_CLASS_P (arg1))
+      else
        {
-         tem = fold_binary_op_with_conditional_arg (code, type, op0, op1,
-                                                    arg1, arg0, 
-                                                    /*cond_first_p=*/0);
-         if (tem != NULL_TREE)
-           return tem;
+         /* Strip any conversions that don't change the mode.  This
+            is safe for every expression, except for a comparison
+            expression because its signedness is derived from its
+            operands.
+
+            Note that this is done as an internal manipulation within
+            the constant folder, in order to find the simplest
+            representation of the arguments so that their form can be
+            studied.  In any cases, the appropriate type conversions
+            should be put back in the tree that will get out of the
+            constant folder.  */
+         STRIP_NOPS (arg0);
        }
     }
 
-  switch (code)
+  if (TREE_CODE_CLASS (code) == tcc_unary)
     {
-    case PLUS_EXPR:
-      /* A + (-B) -> A - B */
-      if (TREE_CODE (arg1) == NEGATE_EXPR)
-       return fold_build2 (MINUS_EXPR, type,
-                           fold_convert (type, arg0),
-                           fold_convert (type, TREE_OPERAND (arg1, 0)));
-      /* (-A) + B -> B - A */
-      if (TREE_CODE (arg0) == NEGATE_EXPR
-         && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
-       return fold_build2 (MINUS_EXPR, type,
-                           fold_convert (type, arg1),
-                           fold_convert (type, TREE_OPERAND (arg0, 0)));
-      /* Convert ~A + 1 to -A.  */
-      if (INTEGRAL_TYPE_P (type)
-         && TREE_CODE (arg0) == BIT_NOT_EXPR
-         && integer_onep (arg1))
-       return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
-
-      if (! FLOAT_TYPE_P (type))
+      if (TREE_CODE (arg0) == COMPOUND_EXPR)
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                      fold_build1 (code, type, TREE_OPERAND (arg0, 1)));
+      else if (TREE_CODE (arg0) == COND_EXPR)
        {
-         if (integer_zerop (arg1))
-           return non_lvalue (fold_convert (type, arg0));
+         tree arg01 = TREE_OPERAND (arg0, 1);
+         tree arg02 = TREE_OPERAND (arg0, 2);
+         if (! VOID_TYPE_P (TREE_TYPE (arg01)))
+           arg01 = fold_build1 (code, type, arg01);
+         if (! VOID_TYPE_P (TREE_TYPE (arg02)))
+           arg02 = fold_build1 (code, type, arg02);
+         tem = fold_build3 (COND_EXPR, type, TREE_OPERAND (arg0, 0),
+                            arg01, arg02);
 
-         /* If we are adding two BIT_AND_EXPR's, both of which are and'ing
-            with a constant, and the two constants have no bits in common,
-            we should treat this as a BIT_IOR_EXPR since this may produce more
+         /* If this was a conversion, and all we did was to move into
+            inside the COND_EXPR, bring it back out.  But leave it if
+            it is a conversion from integer to integer and the
+            result precision is no wider than a word since such a
+            conversion is cheap and may be optimized away by combine,
+            while it couldn't if it were outside the COND_EXPR.  Then return
+            so we don't get into an infinite recursion loop taking the
+            conversion out and then back in.  */
+
+         if ((code == NOP_EXPR || code == CONVERT_EXPR
+              || code == NON_LVALUE_EXPR)
+             && TREE_CODE (tem) == COND_EXPR
+             && TREE_CODE (TREE_OPERAND (tem, 1)) == code
+             && TREE_CODE (TREE_OPERAND (tem, 2)) == code
+             && ! VOID_TYPE_P (TREE_OPERAND (tem, 1))
+             && ! VOID_TYPE_P (TREE_OPERAND (tem, 2))
+             && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))
+                 == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0)))
+             && (! (INTEGRAL_TYPE_P (TREE_TYPE (tem))
+                    && (INTEGRAL_TYPE_P
+                        (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))))
+                    && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD)
+                 || flag_syntax_only))
+           tem = build1 (code, type,
+                         build3 (COND_EXPR,
+                                 TREE_TYPE (TREE_OPERAND
+                                            (TREE_OPERAND (tem, 1), 0)),
+                                 TREE_OPERAND (tem, 0),
+                                 TREE_OPERAND (TREE_OPERAND (tem, 1), 0),
+                                 TREE_OPERAND (TREE_OPERAND (tem, 2), 0)));
+         return tem;
+       }
+      else if (COMPARISON_CLASS_P (arg0))
+       {
+         if (TREE_CODE (type) == BOOLEAN_TYPE)
+           {
+             arg0 = copy_node (arg0);
+             TREE_TYPE (arg0) = type;
+             return arg0;
+           }
+         else if (TREE_CODE (type) != INTEGER_TYPE)
+           return fold_build3 (COND_EXPR, type, arg0,
+                               fold_build1 (code, type,
+                                            integer_one_node),
+                               fold_build1 (code, type,
+                                            integer_zero_node));
+       }
+   }
+
+  switch (code)
+    {
+    case NOP_EXPR:
+    case FLOAT_EXPR:
+    case CONVERT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FIX_CEIL_EXPR:
+    case FIX_FLOOR_EXPR:
+    case FIX_ROUND_EXPR:
+      if (TREE_TYPE (op0) == type)
+       return op0;
+      
+      /* If we have (type) (a CMP b) and type is an integral type, return
+         new expression involving the new type.  */
+      if (COMPARISON_CLASS_P (op0) && INTEGRAL_TYPE_P (type))
+       return fold_build2 (TREE_CODE (op0), type, TREE_OPERAND (op0, 0),
+                           TREE_OPERAND (op0, 1));
+
+      /* Handle cases of two conversions in a row.  */
+      if (TREE_CODE (op0) == NOP_EXPR
+         || TREE_CODE (op0) == CONVERT_EXPR)
+       {
+         tree inside_type = TREE_TYPE (TREE_OPERAND (op0, 0));
+         tree inter_type = TREE_TYPE (op0);
+         int inside_int = INTEGRAL_TYPE_P (inside_type);
+         int inside_ptr = POINTER_TYPE_P (inside_type);
+         int inside_float = FLOAT_TYPE_P (inside_type);
+         int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
+         unsigned int inside_prec = TYPE_PRECISION (inside_type);
+         int inside_unsignedp = TYPE_UNSIGNED (inside_type);
+         int inter_int = INTEGRAL_TYPE_P (inter_type);
+         int inter_ptr = POINTER_TYPE_P (inter_type);
+         int inter_float = FLOAT_TYPE_P (inter_type);
+         int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
+         unsigned int inter_prec = TYPE_PRECISION (inter_type);
+         int inter_unsignedp = TYPE_UNSIGNED (inter_type);
+         int final_int = INTEGRAL_TYPE_P (type);
+         int final_ptr = POINTER_TYPE_P (type);
+         int final_float = FLOAT_TYPE_P (type);
+         int final_vec = TREE_CODE (type) == VECTOR_TYPE;
+         unsigned int final_prec = TYPE_PRECISION (type);
+         int final_unsignedp = TYPE_UNSIGNED (type);
+
+         /* In addition to the cases of two conversions in a row
+            handled below, if we are converting something to its own
+            type via an object of identical or wider precision, neither
+            conversion is needed.  */
+         if (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (type)
+             && ((inter_int && final_int) || (inter_float && final_float))
+             && inter_prec >= final_prec)
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
+
+         /* Likewise, if the intermediate and final types are either both
+            float or both integer, we don't need the middle conversion if
+            it is wider than the final type and doesn't change the signedness
+            (for integers).  Avoid this if the final type is a pointer
+            since then we sometimes need the inner conversion.  Likewise if
+            the outer has a precision not equal to the size of its mode.  */
+         if ((((inter_int || inter_ptr) && (inside_int || inside_ptr))
+              || (inter_float && inside_float)
+              || (inter_vec && inside_vec))
+             && inter_prec >= inside_prec
+             && (inter_float || inter_vec
+                 || inter_unsignedp == inside_unsignedp)
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+                   && TYPE_MODE (type) == TYPE_MODE (inter_type))
+             && ! final_ptr
+             && (! final_vec || inter_prec == inside_prec))
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
+
+         /* If we have a sign-extension of a zero-extended value, we can
+            replace that by a single zero-extension.  */
+         if (inside_int && inter_int && final_int
+             && inside_prec < inter_prec && inter_prec < final_prec
+             && inside_unsignedp && !inter_unsignedp)
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
+
+         /* Two conversions in a row are not needed unless:
+            - some conversion is floating-point (overstrict for now), or
+            - some conversion is a vector (overstrict for now), or
+            - the intermediate type is narrower than both initial and
+              final, or
+            - the intermediate type and innermost type differ in signedness,
+              and the outermost type is wider than the intermediate, or
+            - the initial type is a pointer type and the precisions of the
+              intermediate and final types differ, or
+            - the final type is a pointer type and the precisions of the
+              initial and intermediate types differ.  */
+         if (! inside_float && ! inter_float && ! final_float
+             && ! inside_vec && ! inter_vec && ! final_vec
+             && (inter_prec > inside_prec || inter_prec > final_prec)
+             && ! (inside_int && inter_int
+                   && inter_unsignedp != inside_unsignedp
+                   && inter_prec < final_prec)
+             && ((inter_unsignedp && inter_prec > inside_prec)
+                 == (final_unsignedp && final_prec > inter_prec))
+             && ! (inside_ptr && inter_prec != final_prec)
+             && ! (final_ptr && inside_prec != inter_prec)
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+                   && TYPE_MODE (type) == TYPE_MODE (inter_type))
+             && ! final_ptr)
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
+       }
+
+      /* Handle (T *)&A.B.C for A being of type T and B and C
+        living at offset zero.  This occurs frequently in
+        C++ upcasting and then accessing the base.  */
+      if (TREE_CODE (op0) == ADDR_EXPR
+         && POINTER_TYPE_P (type)
+         && handled_component_p (TREE_OPERAND (op0, 0)))
+        {
+         HOST_WIDE_INT bitsize, bitpos;
+         tree offset;
+         enum machine_mode mode;
+         int unsignedp, volatilep;
+          tree base = TREE_OPERAND (op0, 0);
+         base = get_inner_reference (base, &bitsize, &bitpos, &offset,
+                                     &mode, &unsignedp, &volatilep, false);
+         /* If the reference was to a (constant) zero offset, we can use
+            the address of the base if it has the same base type
+            as the result type.  */
+         if (! offset && bitpos == 0
+             && TYPE_MAIN_VARIANT (TREE_TYPE (type))
+                 == TYPE_MAIN_VARIANT (TREE_TYPE (base)))
+           return fold_convert (type, build_fold_addr_expr (base));
+        }
+
+      if (TREE_CODE (op0) == MODIFY_EXPR
+         && TREE_CONSTANT (TREE_OPERAND (op0, 1))
+         /* Detect assigning a bitfield.  */
+         && !(TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF
+              && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (op0, 0), 1))))
+       {
+         /* Don't leave an assignment inside a conversion
+            unless assigning a bitfield.  */
+         tem = fold_build1 (code, type, TREE_OPERAND (op0, 1));
+         /* First do the assignment, then return converted constant.  */
+         tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, tem);
+         TREE_NO_WARNING (tem) = 1;
+         TREE_USED (tem) = 1;
+         return tem;
+       }
+
+      /* Convert (T)(x & c) into (T)x & (T)c, if c is an integer
+        constants (if x has signed type, the sign bit cannot be set
+        in c).  This folds extension into the BIT_AND_EXPR.  */
+      if (INTEGRAL_TYPE_P (type)
+         && TREE_CODE (type) != BOOLEAN_TYPE
+         && TREE_CODE (op0) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST)
+       {
+         tree and = op0;
+         tree and0 = TREE_OPERAND (and, 0), and1 = TREE_OPERAND (and, 1);
+         int change = 0;
+
+         if (TYPE_UNSIGNED (TREE_TYPE (and))
+             || (TYPE_PRECISION (type)
+                 <= TYPE_PRECISION (TREE_TYPE (and))))
+           change = 1;
+         else if (TYPE_PRECISION (TREE_TYPE (and1))
+                  <= HOST_BITS_PER_WIDE_INT
+                  && host_integerp (and1, 1))
+           {
+             unsigned HOST_WIDE_INT cst;
+
+             cst = tree_low_cst (and1, 1);
+             cst &= (HOST_WIDE_INT) -1
+                    << (TYPE_PRECISION (TREE_TYPE (and1)) - 1);
+             change = (cst == 0);
+#ifdef LOAD_EXTEND_OP
+             if (change
+                 && !flag_syntax_only
+                 && (LOAD_EXTEND_OP (TYPE_MODE (TREE_TYPE (and0)))
+                     == ZERO_EXTEND))
+               {
+                 tree uns = lang_hooks.types.unsigned_type (TREE_TYPE (and0));
+                 and0 = fold_convert (uns, and0);
+                 and1 = fold_convert (uns, and1);
+               }
+#endif
+           }
+         if (change)
+           {
+             tem = build_int_cst_wide (type, TREE_INT_CST_LOW (and1),
+                                       TREE_INT_CST_HIGH (and1));
+             tem = force_fit_type (tem, 0, TREE_OVERFLOW (and1),
+                                   TREE_CONSTANT_OVERFLOW (and1));
+             return fold_build2 (BIT_AND_EXPR, type,
+                                 fold_convert (type, and0), tem);
+           }
+       }
+
+      /* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and
+        T2 being pointers to types of the same size.  */
+      if (POINTER_TYPE_P (type)
+         && BINARY_CLASS_P (arg0)
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
+         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+       {
+         tree arg00 = TREE_OPERAND (arg0, 0);
+         tree t0 = type;
+         tree t1 = TREE_TYPE (arg00);
+         tree tt0 = TREE_TYPE (t0);
+         tree tt1 = TREE_TYPE (t1);
+         tree s0 = TYPE_SIZE (tt0);
+         tree s1 = TYPE_SIZE (tt1);
+
+         if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST))
+           return build2 (TREE_CODE (arg0), t0, fold_convert (t0, arg00),
+                          TREE_OPERAND (arg0, 1));
+       }
+
+      /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types
+        of the same precision, and X is a integer type not narrower than
+        types T1 or T2, i.e. the cast (T2)X isn't an extension.  */
+      if (INTEGRAL_TYPE_P (type)
+         && TREE_CODE (op0) == BIT_NOT_EXPR
+         && INTEGRAL_TYPE_P (TREE_TYPE (op0))
+         && (TREE_CODE (TREE_OPERAND (op0, 0)) == NOP_EXPR
+             || TREE_CODE (TREE_OPERAND (op0, 0)) == CONVERT_EXPR)
+         && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (op0)))
+       {
+         tem = TREE_OPERAND (TREE_OPERAND (op0, 0), 0);
+         if (INTEGRAL_TYPE_P (TREE_TYPE (tem))
+             && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (tem)))
+           return fold_build1 (BIT_NOT_EXPR, type, fold_convert (type, tem));
+       }
+
+      tem = fold_convert_const (code, type, arg0);
+      return tem ? tem : NULL_TREE;
+
+    case VIEW_CONVERT_EXPR:
+      if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
+       return fold_build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
+      return fold_view_convert_expr (type, op0);
+
+    case NEGATE_EXPR:
+      if (negate_expr_p (arg0))
+       return fold_convert (type, negate_expr (arg0));
+      return NULL_TREE;
+
+    case ABS_EXPR:
+      if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST)
+       return fold_abs_const (arg0, type);
+      else if (TREE_CODE (arg0) == NEGATE_EXPR)
+       return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
+      /* Convert fabs((double)float) into (double)fabsf(float).  */
+      else if (TREE_CODE (arg0) == NOP_EXPR
+              && TREE_CODE (type) == REAL_TYPE)
+       {
+         tree targ0 = strip_float_extensions (arg0);
+         if (targ0 != arg0)
+           return fold_convert (type, fold_build1 (ABS_EXPR,
+                                                   TREE_TYPE (targ0),
+                                                   targ0));
+       }
+      /* ABS_EXPR<ABS_EXPR<x>> = ABS_EXPR<x> even if flag_wrapv is on.  */
+      else if (tree_expr_nonnegative_p (arg0) || TREE_CODE (arg0) == ABS_EXPR)
+       return arg0;
+
+      /* Strip sign ops from argument.  */
+      if (TREE_CODE (type) == REAL_TYPE)
+       {
+         tem = fold_strip_sign_ops (arg0);
+         if (tem)
+           return fold_build1 (ABS_EXPR, type, fold_convert (type, tem));
+       }
+      return NULL_TREE;
+
+    case CONJ_EXPR:
+      if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
+       return fold_convert (type, arg0);
+      else if (TREE_CODE (arg0) == COMPLEX_EXPR)
+       return build2 (COMPLEX_EXPR, type,
+                      TREE_OPERAND (arg0, 0),
+                      negate_expr (TREE_OPERAND (arg0, 1)));
+      else if (TREE_CODE (arg0) == COMPLEX_CST)
+       return build_complex (type, TREE_REALPART (arg0),
+                             negate_expr (TREE_IMAGPART (arg0)));
+      else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+       return fold_build2 (TREE_CODE (arg0), type,
+                           fold_build1 (CONJ_EXPR, type,
+                                        TREE_OPERAND (arg0, 0)),
+                           fold_build1 (CONJ_EXPR, type,
+                                        TREE_OPERAND (arg0, 1)));
+      else if (TREE_CODE (arg0) == CONJ_EXPR)
+       return TREE_OPERAND (arg0, 0);
+      return NULL_TREE;
+
+    case BIT_NOT_EXPR:
+      if (TREE_CODE (arg0) == INTEGER_CST)
+        return fold_not_const (arg0, type);
+      else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
+       return TREE_OPERAND (arg0, 0);
+      /* Convert ~ (-A) to A - 1.  */
+      else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
+       return fold_build2 (MINUS_EXPR, type, TREE_OPERAND (arg0, 0),
+                           build_int_cst (type, 1));
+      /* Convert ~ (A - 1) or ~ (A + -1) to -A.  */
+      else if (INTEGRAL_TYPE_P (type)
+              && ((TREE_CODE (arg0) == MINUS_EXPR
+                   && integer_onep (TREE_OPERAND (arg0, 1)))
+                  || (TREE_CODE (arg0) == PLUS_EXPR
+                      && integer_all_onesp (TREE_OPERAND (arg0, 1)))))
+       return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
+      /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify.  */
+      else if (TREE_CODE (arg0) == BIT_XOR_EXPR
+              && (tem = fold_unary (BIT_NOT_EXPR, type,
+                                    fold_convert (type,
+                                                  TREE_OPERAND (arg0, 0)))))
+       return fold_build2 (BIT_XOR_EXPR, type, tem,
+                           fold_convert (type, TREE_OPERAND (arg0, 1)));
+      else if (TREE_CODE (arg0) == BIT_XOR_EXPR
+              && (tem = fold_unary (BIT_NOT_EXPR, type,
+                                    fold_convert (type,
+                                                  TREE_OPERAND (arg0, 1)))))
+       return fold_build2 (BIT_XOR_EXPR, type,
+                           fold_convert (type, TREE_OPERAND (arg0, 0)), tem);
+
+      return NULL_TREE;
+
+    case TRUTH_NOT_EXPR:
+      /* The argument to invert_truthvalue must have Boolean type.  */
+      if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
+          arg0 = fold_convert (boolean_type_node, arg0);
+
+      /* Note that the operand of this must be an int
+        and its values must be 0 or 1.
+        ("true" is a fixed value perhaps depending on the language,
+        but we don't handle values other than 1 correctly yet.)  */
+      tem = invert_truthvalue (arg0);
+      /* Avoid infinite recursion.  */
+      if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
+       return NULL_TREE;
+      return fold_convert (type, tem);
+
+    case REALPART_EXPR:
+      if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
+       return NULL_TREE;
+      else if (TREE_CODE (arg0) == COMPLEX_EXPR)
+       return omit_one_operand (type, TREE_OPERAND (arg0, 0),
+                                TREE_OPERAND (arg0, 1));
+      else if (TREE_CODE (arg0) == COMPLEX_CST)
+       return TREE_REALPART (arg0);
+      else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+       return fold_build2 (TREE_CODE (arg0), type,
+                           fold_build1 (REALPART_EXPR, type,
+                                        TREE_OPERAND (arg0, 0)),
+                           fold_build1 (REALPART_EXPR, type,
+                                        TREE_OPERAND (arg0, 1)));
+      return NULL_TREE;
+
+    case IMAGPART_EXPR:
+      if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
+       return fold_convert (type, integer_zero_node);
+      else if (TREE_CODE (arg0) == COMPLEX_EXPR)
+       return omit_one_operand (type, TREE_OPERAND (arg0, 1),
+                                TREE_OPERAND (arg0, 0));
+      else if (TREE_CODE (arg0) == COMPLEX_CST)
+       return TREE_IMAGPART (arg0);
+      else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+       return fold_build2 (TREE_CODE (arg0), type,
+                           fold_build1 (IMAGPART_EXPR, type,
+                                        TREE_OPERAND (arg0, 0)),
+                           fold_build1 (IMAGPART_EXPR, type,
+                                        TREE_OPERAND (arg0, 1)));
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    } /* switch (code) */
+}
+
+/* Fold a binary expression of code CODE and type TYPE with operands
+   OP0 and OP1, containing either a MIN-MAX or a MAX-MIN combination.
+   Return the folded expression if folding is successful.  Otherwise,
+   return NULL_TREE.  */
+
+static tree
+fold_minmax (enum tree_code code, tree type, tree op0, tree op1)
+{
+  enum tree_code compl_code;
+
+  if (code == MIN_EXPR)
+    compl_code = MAX_EXPR;
+  else if (code == MAX_EXPR)
+    compl_code = MIN_EXPR;
+  else
+    gcc_unreachable ();
+
+  /* MIN (MAX (a, b), b) == b. Â */
+  if (TREE_CODE (op0) == compl_code
+      && operand_equal_p (TREE_OPERAND (op0, 1), op1, 0))
+    return omit_one_operand (type, op1, TREE_OPERAND (op0, 0));
+
+  /* MIN (MAX (b, a), b) == b. Â */
+  if (TREE_CODE (op0) == compl_code
+      && operand_equal_p (TREE_OPERAND (op0, 0), op1, 0)
+      && reorder_operands_p (TREE_OPERAND (op0, 1), op1))
+    return omit_one_operand (type, op1, TREE_OPERAND (op0, 1));
+
+  /* MIN (a, MAX (a, b)) == a. Â */
+  if (TREE_CODE (op1) == compl_code
+      && operand_equal_p (op0, TREE_OPERAND (op1, 0), 0)
+      && reorder_operands_p (op0, TREE_OPERAND (op1, 1)))
+    return omit_one_operand (type, op0, TREE_OPERAND (op1, 1));
+
+  /* MIN (a, MAX (b, a)) == a. Â */
+  if (TREE_CODE (op1) == compl_code
+      && operand_equal_p (op0, TREE_OPERAND (op1, 1), 0)
+      && reorder_operands_p (op0, TREE_OPERAND (op1, 0)))
+    return omit_one_operand (type, op0, TREE_OPERAND (op1, 0));
+
+  return NULL_TREE;
+}
+
+/* Subroutine of fold_binary.  This routine performs all of the
+   transformations that are common to the equality/inequality
+   operators (EQ_EXPR and NE_EXPR) and the ordering operators
+   (LT_EXPR, LE_EXPR, GE_EXPR and GT_EXPR).  Callers other than
+   fold_binary should call fold_binary.  Fold a comparison with
+   tree code CODE and type TYPE with operands OP0 and OP1.  Return
+   the folded comparison or NULL_TREE.  */
+
+static tree
+fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
+{
+  tree arg0, arg1, tem;
+
+  arg0 = op0;
+  arg1 = op1;
+
+  STRIP_SIGN_NOPS (arg0);
+  STRIP_SIGN_NOPS (arg1);
+
+  tem = fold_relational_const (code, type, arg0, arg1);
+  if (tem != NULL_TREE)
+    return tem;
+
+  /* If one arg is a real or integer constant, put it last.  */
+  if (tree_swap_operands_p (arg0, arg1, true))
+    return fold_build2 (swap_tree_comparison (code), type, op1, op0);
+
+  /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 +- C1.  */
+  if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+      && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+         && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
+         && !TYPE_UNSIGNED (TREE_TYPE (arg1))
+         && !(flag_wrapv || flag_trapv))
+      && (TREE_CODE (arg1) == INTEGER_CST
+         && !TREE_OVERFLOW (arg1)))
+    {
+      tree const1 = TREE_OPERAND (arg0, 1);
+      tree const2 = arg1;
+      tree variable = TREE_OPERAND (arg0, 0);
+      tree lhs;
+      int lhs_add;
+      lhs_add = TREE_CODE (arg0) != PLUS_EXPR;
+
+      lhs = fold_build2 (lhs_add ? PLUS_EXPR : MINUS_EXPR,
+                        TREE_TYPE (arg1), const2, const1);
+      if (TREE_CODE (lhs) == TREE_CODE (arg1)
+         && (TREE_CODE (lhs) != INTEGER_CST
+             || !TREE_OVERFLOW (lhs)))
+       return fold_build2 (code, type, variable, lhs);
+    }
+
+  if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
+    {
+      tree targ0 = strip_float_extensions (arg0);
+      tree targ1 = strip_float_extensions (arg1);
+      tree newtype = TREE_TYPE (targ0);
+
+      if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
+       newtype = TREE_TYPE (targ1);
+
+      /* Fold (double)float1 CMP (double)float2 into float1 CMP float2.  */
+      if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
+       return fold_build2 (code, type, fold_convert (newtype, targ0),
+                           fold_convert (newtype, targ1));
+
+      /* (-a) CMP (-b) -> b CMP a  */
+      if (TREE_CODE (arg0) == NEGATE_EXPR
+         && TREE_CODE (arg1) == NEGATE_EXPR)
+       return fold_build2 (code, type, TREE_OPERAND (arg1, 0),
+                           TREE_OPERAND (arg0, 0));
+
+      if (TREE_CODE (arg1) == REAL_CST)
+       {
+         REAL_VALUE_TYPE cst;
+         cst = TREE_REAL_CST (arg1);
+
+         /* (-a) CMP CST -> a swap(CMP) (-CST)  */
+         if (TREE_CODE (arg0) == NEGATE_EXPR)
+           return fold_build2 (swap_tree_comparison (code), type,
+                               TREE_OPERAND (arg0, 0),
+                               build_real (TREE_TYPE (arg1),
+                                           REAL_VALUE_NEGATE (cst)));
+
+         /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
+         /* a CMP (-0) -> a CMP 0  */
+         if (REAL_VALUE_MINUS_ZERO (cst))
+           return fold_build2 (code, type, arg0,
+                               build_real (TREE_TYPE (arg1), dconst0));
+
+         /* x != NaN is always true, other ops are always false.  */
+         if (REAL_VALUE_ISNAN (cst)
+             && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
+           {
+             tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
+             return omit_one_operand (type, tem, arg0);
+           }
+
+         /* Fold comparisons against infinity.  */
+         if (REAL_VALUE_ISINF (cst))
+           {
+             tem = fold_inf_compare (code, type, arg0, arg1);
+             if (tem != NULL_TREE)
+               return tem;
+           }
+       }
+
+      /* If this is a comparison of a real constant with a PLUS_EXPR
+        or a MINUS_EXPR of a real constant, we can convert it into a
+        comparison with a revised real constant as long as no overflow
+        occurs when unsafe_math_optimizations are enabled.  */
+      if (flag_unsafe_math_optimizations
+         && TREE_CODE (arg1) == REAL_CST
+         && (TREE_CODE (arg0) == PLUS_EXPR
+             || TREE_CODE (arg0) == MINUS_EXPR)
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+         && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
+                                     ? MINUS_EXPR : PLUS_EXPR,
+                                     arg1, TREE_OPERAND (arg0, 1), 0))
+         && ! TREE_CONSTANT_OVERFLOW (tem))
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
+
+      /* Likewise, we can simplify a comparison of a real constant with
+         a MINUS_EXPR whose first operand is also a real constant, i.e.
+         (c1 - x) < c2 becomes x > c1-c2.  */
+      if (flag_unsafe_math_optimizations
+         && TREE_CODE (arg1) == REAL_CST
+         && TREE_CODE (arg0) == MINUS_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
+         && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
+                                     arg1, 0))
+         && ! TREE_CONSTANT_OVERFLOW (tem))
+       return fold_build2 (swap_tree_comparison (code), type,
+                           TREE_OPERAND (arg0, 1), tem);
+
+      /* Fold comparisons against built-in math functions.  */
+      if (TREE_CODE (arg1) == REAL_CST
+         && flag_unsafe_math_optimizations
+         && ! flag_errno_math)
+       {
+         enum built_in_function fcode = builtin_mathfn_code (arg0);
+
+         if (fcode != END_BUILTINS)
+           {
+             tem = fold_mathfn_compare (fcode, code, type, arg0, arg1);
+             if (tem != NULL_TREE)
+               return tem;
+           }
+       }
+    }
+
+  /* Convert foo++ == CONST into ++foo == CONST + INCR.  */
+  if (TREE_CONSTANT (arg1)
+      && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
+         || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
+      /* This optimization is invalid for ordered comparisons
+         if CONST+INCR overflows or if foo+incr might overflow.
+        This optimization is invalid for floating point due to rounding.
+        For pointer types we assume overflow doesn't happen.  */
+      && (POINTER_TYPE_P (TREE_TYPE (arg0))
+         || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+             && (code == EQ_EXPR || code == NE_EXPR))))
+    {
+      tree varop, newconst;
+
+      if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
+       {
+         newconst = fold_build2 (PLUS_EXPR, TREE_TYPE (arg0),
+                                 arg1, TREE_OPERAND (arg0, 1));
+         varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0),
+                         TREE_OPERAND (arg0, 0),
+                         TREE_OPERAND (arg0, 1));
+       }
+      else
+       {
+         newconst = fold_build2 (MINUS_EXPR, TREE_TYPE (arg0),
+                                 arg1, TREE_OPERAND (arg0, 1));
+         varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0),
+                         TREE_OPERAND (arg0, 0),
+                         TREE_OPERAND (arg0, 1));
+       }
+
+
+      /* If VAROP is a reference to a bitfield, we must mask
+        the constant by the width of the field.  */
+      if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
+         && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
+         && host_integerp (DECL_SIZE (TREE_OPERAND
+                                        (TREE_OPERAND (varop, 0), 1)), 1))
+       {
+         tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
+         HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
+         tree folded_compare, shift;
+
+         /* First check whether the comparison would come out
+            always the same.  If we don't do that we would
+            change the meaning with the masking.  */
+         folded_compare = fold_build2 (code, type,
+                                       TREE_OPERAND (varop, 0), arg1);
+         if (TREE_CODE (folded_compare) == INTEGER_CST)
+           return omit_one_operand (type, folded_compare, varop);
+
+         shift = build_int_cst (NULL_TREE,
+                                TYPE_PRECISION (TREE_TYPE (varop)) - size);
+         shift = fold_convert (TREE_TYPE (varop), shift);
+         newconst = fold_build2 (LSHIFT_EXPR, TREE_TYPE (varop),
+                                 newconst, shift);
+         newconst = fold_build2 (RSHIFT_EXPR, TREE_TYPE (varop),
+                                 newconst, shift);
+       }
+
+      return fold_build2 (code, type, varop, newconst);
+    }
+
+  if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
+      && (TREE_CODE (arg0) == NOP_EXPR
+         || TREE_CODE (arg0) == CONVERT_EXPR))
+    {
+      /* If we are widening one operand of an integer comparison,
+        see if the other operand is similarly being widened.  Perhaps we
+        can do the comparison in the narrower type.  */
+      tem = fold_widened_comparison (code, type, arg0, arg1);
+      if (tem)
+       return tem;
+
+      /* Or if we are changing signedness.  */
+      tem = fold_sign_changed_comparison (code, type, arg0, arg1);
+      if (tem)
+       return tem;
+    }
+
+  /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a
+     constant, we can simplify it.  */
+  if (TREE_CODE (arg1) == INTEGER_CST
+      && (TREE_CODE (arg0) == MIN_EXPR
+         || TREE_CODE (arg0) == MAX_EXPR)
+      && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+    {
+      tem = optimize_minmax_comparison (code, type, op0, op1);
+      if (tem)
+       return tem;
+    }
+
+  /* Simplify comparison of something with itself.  (For IEEE
+     floating-point, we can only do some of these simplifications.)  */
+  if (operand_equal_p (arg0, arg1, 0))
+    {
+      switch (code)
+       {
+       case EQ_EXPR:
+         if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
+             || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+           return constant_boolean_node (1, type);
+         break;
+
+       case GE_EXPR:
+       case LE_EXPR:
+         if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
+             || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+           return constant_boolean_node (1, type);
+         return fold_build2 (EQ_EXPR, type, arg0, arg1);
+
+       case NE_EXPR:
+         /* For NE, we can only do this simplification if integer
+            or we don't honor IEEE floating point NaNs.  */
+         if (FLOAT_TYPE_P (TREE_TYPE (arg0))
+             && HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+           break;
+         /* ... fall through ...  */
+       case GT_EXPR:
+       case LT_EXPR:
+         return constant_boolean_node (0, type);
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  /* If we are comparing an expression that just has comparisons
+     of two integer values, arithmetic expressions of those comparisons,
+     and constants, we can simplify it.  There are only three cases
+     to check: the two values can either be equal, the first can be
+     greater, or the second can be greater.  Fold the expression for
+     those three values.  Since each value must be 0 or 1, we have
+     eight possibilities, each of which corresponds to the constant 0
+     or 1 or one of the six possible comparisons.
+
+     This handles common cases like (a > b) == 0 but also handles
+     expressions like  ((x > y) - (y > x)) > 0, which supposedly
+     occur in macroized code.  */
+
+  if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST)
+    {
+      tree cval1 = 0, cval2 = 0;
+      int save_p = 0;
+
+      if (twoval_comparison_p (arg0, &cval1, &cval2, &save_p)
+         /* Don't handle degenerate cases here; they should already
+            have been handled anyway.  */
+         && cval1 != 0 && cval2 != 0
+         && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
+         && TREE_TYPE (cval1) == TREE_TYPE (cval2)
+         && INTEGRAL_TYPE_P (TREE_TYPE (cval1))
+         && TYPE_MAX_VALUE (TREE_TYPE (cval1))
+         && TYPE_MAX_VALUE (TREE_TYPE (cval2))
+         && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
+                               TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
+       {
+         tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1));
+         tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1));
+
+         /* We can't just pass T to eval_subst in case cval1 or cval2
+            was the same as ARG1.  */
+
+         tree high_result
+               = fold_build2 (code, type,
+                              eval_subst (arg0, cval1, maxval,
+                                          cval2, minval),
+                              arg1);
+         tree equal_result
+               = fold_build2 (code, type,
+                              eval_subst (arg0, cval1, maxval,
+                                          cval2, maxval),
+                              arg1);
+         tree low_result
+               = fold_build2 (code, type,
+                              eval_subst (arg0, cval1, minval,
+                                          cval2, maxval),
+                              arg1);
+
+         /* All three of these results should be 0 or 1.  Confirm they are.
+            Then use those values to select the proper code to use.  */
+
+         if (TREE_CODE (high_result) == INTEGER_CST
+             && TREE_CODE (equal_result) == INTEGER_CST
+             && TREE_CODE (low_result) == INTEGER_CST)
+           {
+             /* Make a 3-bit mask with the high-order bit being the
+                value for `>', the next for '=', and the low for '<'.  */
+             switch ((integer_onep (high_result) * 4)
+                     + (integer_onep (equal_result) * 2)
+                     + integer_onep (low_result))
+               {
+               case 0:
+                 /* Always false.  */
+                 return omit_one_operand (type, integer_zero_node, arg0);
+               case 1:
+                 code = LT_EXPR;
+                 break;
+               case 2:
+                 code = EQ_EXPR;
+                 break;
+               case 3:
+                 code = LE_EXPR;
+                 break;
+               case 4:
+                 code = GT_EXPR;
+                 break;
+               case 5:
+                 code = NE_EXPR;
+                 break;
+               case 6:
+                 code = GE_EXPR;
+                 break;
+               case 7:
+                 /* Always true.  */
+                 return omit_one_operand (type, integer_one_node, arg0);
+               }
+
+             if (save_p)
+               return save_expr (build2 (code, type, cval1, cval2));
+             return fold_build2 (code, type, cval1, cval2);
+           }
+       }
+    }
+
+  /* Fold a comparison of the address of COMPONENT_REFs with the same
+     type and component to a comparison of the address of the base
+     object.  In short, &x->a OP &y->a to x OP y and
+     &x->a OP &y.a to x OP &y  */
+  if (TREE_CODE (arg0) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF
+      && TREE_CODE (arg1) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF)
+    {
+      tree cref0 = TREE_OPERAND (arg0, 0);
+      tree cref1 = TREE_OPERAND (arg1, 0);
+      if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1))
+       {
+         tree op0 = TREE_OPERAND (cref0, 0);
+         tree op1 = TREE_OPERAND (cref1, 0);
+         return fold_build2 (code, type,
+                             build_fold_addr_expr (op0),
+                             build_fold_addr_expr (op1));
+       }
+    }
+
+  /* We can fold X/C1 op C2 where C1 and C2 are integer constants
+     into a single range test.  */
+  if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
+       || TREE_CODE (arg0) == EXACT_DIV_EXPR)
+      && TREE_CODE (arg1) == INTEGER_CST
+      && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+      && !integer_zerop (TREE_OPERAND (arg0, 1))
+      && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
+      && !TREE_OVERFLOW (arg1))
+    {
+      tem = fold_div_compare (code, type, arg0, arg1);
+      if (tem != NULL_TREE)
+       return tem;
+    }
+
+  return NULL_TREE;
+}
+
+/* Fold a binary expression of code CODE and type TYPE with operands
+   OP0 and OP1.  Return the folded expression if folding is
+   successful.  Otherwise, return NULL_TREE.  */
+
+tree
+fold_binary (enum tree_code code, tree type, tree op0, tree op1)
+{
+  enum tree_code_class kind = TREE_CODE_CLASS (code);
+  tree arg0, arg1, tem;
+  tree t1 = NULL_TREE;
+
+  gcc_assert (IS_EXPR_CODE_CLASS (kind)
+             && TREE_CODE_LENGTH (code) == 2
+             && op0 != NULL_TREE
+             && op1 != NULL_TREE);
+
+  arg0 = op0;
+  arg1 = op1;
+
+  /* Strip any conversions that don't change the mode.  This is
+     safe for every expression, except for a comparison expression
+     because its signedness is derived from its operands.  So, in
+     the latter case, only strip conversions that don't change the
+     signedness.
+
+     Note that this is done as an internal manipulation within the
+     constant folder, in order to find the simplest representation
+     of the arguments so that their form can be studied.  In any
+     cases, the appropriate type conversions should be put back in
+     the tree that will get out of the constant folder.  */
+
+  if (kind == tcc_comparison)
+    {
+      STRIP_SIGN_NOPS (arg0);
+      STRIP_SIGN_NOPS (arg1);
+    }
+  else
+    {
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+    }
+
+  /* Note that TREE_CONSTANT isn't enough: static var addresses are
+     constant but we can't do arithmetic on them.  */
+  if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+      || (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
+      || (TREE_CODE (arg0) == COMPLEX_CST && TREE_CODE (arg1) == COMPLEX_CST)
+      || (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST))
+    {
+      if (kind == tcc_binary)
+       tem = const_binop (code, arg0, arg1, 0);
+      else if (kind == tcc_comparison)
+       tem = fold_relational_const (code, type, arg0, arg1);
+      else
+       tem = NULL_TREE;
+
+      if (tem != NULL_TREE)
+       {
+         if (TREE_TYPE (tem) != type)
+           tem = fold_convert (type, tem);
+         return tem;
+       }
+    }
+
+  /* If this is a commutative operation, and ARG0 is a constant, move it
+     to ARG1 to reduce the number of tests below.  */
+  if (commutative_tree_code (code)
+      && tree_swap_operands_p (arg0, arg1, true))
+    return fold_build2 (code, type, op1, op0);
+
+  /* ARG0 is the first operand of EXPR, and ARG1 is the second operand.
+
+     First check for cases where an arithmetic operation is applied to a
+     compound, conditional, or comparison operation.  Push the arithmetic
+     operation inside the compound or conditional to see if any folding
+     can then be done.  Convert comparison to conditional for this purpose.
+     The also optimizes non-constant cases that used to be done in
+     expand_expr.
+
+     Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR,
+     one of the operands is a comparison and the other is a comparison, a
+     BIT_AND_EXPR with the constant 1, or a truth value.  In that case, the
+     code below would make the expression more complex.  Change it to a
+     TRUTH_{AND,OR}_EXPR.  Likewise, convert a similar NE_EXPR to
+     TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR.  */
+
+  if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR
+       || code == EQ_EXPR || code == NE_EXPR)
+      && ((truth_value_p (TREE_CODE (arg0))
+          && (truth_value_p (TREE_CODE (arg1))
+              || (TREE_CODE (arg1) == BIT_AND_EXPR
+                  && integer_onep (TREE_OPERAND (arg1, 1)))))
+         || (truth_value_p (TREE_CODE (arg1))
+             && (truth_value_p (TREE_CODE (arg0))
+                 || (TREE_CODE (arg0) == BIT_AND_EXPR
+                     && integer_onep (TREE_OPERAND (arg0, 1)))))))
+    {
+      tem = fold_build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
+                        : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
+                        : TRUTH_XOR_EXPR,
+                        boolean_type_node,
+                        fold_convert (boolean_type_node, arg0),
+                        fold_convert (boolean_type_node, arg1));
+
+      if (code == EQ_EXPR)
+       tem = invert_truthvalue (tem);
+
+      return fold_convert (type, tem);
+    }
+
+  if (TREE_CODE_CLASS (code) == tcc_binary
+      || TREE_CODE_CLASS (code) == tcc_comparison)
+    {
+      if (TREE_CODE (arg0) == COMPOUND_EXPR)
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                      fold_build2 (code, type,
+                                   TREE_OPERAND (arg0, 1), op1));
+      if (TREE_CODE (arg1) == COMPOUND_EXPR
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+                      fold_build2 (code, type,
+                                   op0, TREE_OPERAND (arg1, 1)));
+
+      if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
+       {
+         tem = fold_binary_op_with_conditional_arg (code, type, op0, op1,
+                                                    arg0, arg1, 
+                                                    /*cond_first_p=*/1);
+         if (tem != NULL_TREE)
+           return tem;
+       }
+
+      if (TREE_CODE (arg1) == COND_EXPR || COMPARISON_CLASS_P (arg1))
+       {
+         tem = fold_binary_op_with_conditional_arg (code, type, op0, op1,
+                                                    arg1, arg0, 
+                                                    /*cond_first_p=*/0);
+         if (tem != NULL_TREE)
+           return tem;
+       }
+    }
+
+  switch (code)
+    {
+    case PLUS_EXPR:
+      /* A + (-B) -> A - B */
+      if (TREE_CODE (arg1) == NEGATE_EXPR)
+       return fold_build2 (MINUS_EXPR, type,
+                           fold_convert (type, arg0),
+                           fold_convert (type, TREE_OPERAND (arg1, 0)));
+      /* (-A) + B -> B - A */
+      if (TREE_CODE (arg0) == NEGATE_EXPR
+         && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
+       return fold_build2 (MINUS_EXPR, type,
+                           fold_convert (type, arg1),
+                           fold_convert (type, TREE_OPERAND (arg0, 0)));
+      /* Convert ~A + 1 to -A.  */
+      if (INTEGRAL_TYPE_P (type)
+         && TREE_CODE (arg0) == BIT_NOT_EXPR
+         && integer_onep (arg1))
+       return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
+
+      /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the
+        same or one.  */
+      if ((TREE_CODE (arg0) == MULT_EXPR
+          || TREE_CODE (arg1) == MULT_EXPR)
+         && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
+        {
+         tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
+         if (tem)
+           return tem;
+       }
+
+      if (! FLOAT_TYPE_P (type))
+       {
+         if (integer_zerop (arg1))
+           return non_lvalue (fold_convert (type, arg0));
+
+         /* If we are adding two BIT_AND_EXPR's, both of which are and'ing
+            with a constant, and the two constants have no bits in common,
+            we should treat this as a BIT_IOR_EXPR since this may produce more
             simplifications.  */
          if (TREE_CODE (arg0) == BIT_AND_EXPR
              && TREE_CODE (arg1) == BIT_AND_EXPR
@@ -7200,70 +8322,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                                               parg1)));
            }
 
-         if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
-           {
-             tree arg00, arg01, arg10, arg11;
-             tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
-
-             /* (A * C) + (B * C) -> (A+B) * C.
-                We are most concerned about the case where C is a constant,
-                but other combinations show up during loop reduction.  Since
-                it is not difficult, try all four possibilities.  */
-
-             arg00 = TREE_OPERAND (arg0, 0);
-             arg01 = TREE_OPERAND (arg0, 1);
-             arg10 = TREE_OPERAND (arg1, 0);
-             arg11 = TREE_OPERAND (arg1, 1);
-             same = NULL_TREE;
-
-             if (operand_equal_p (arg01, arg11, 0))
-               same = arg01, alt0 = arg00, alt1 = arg10;
-             else if (operand_equal_p (arg00, arg10, 0))
-               same = arg00, alt0 = arg01, alt1 = arg11;
-             else if (operand_equal_p (arg00, arg11, 0))
-               same = arg00, alt0 = arg01, alt1 = arg10;
-             else if (operand_equal_p (arg01, arg10, 0))
-               same = arg01, alt0 = arg00, alt1 = arg11;
-
-             /* No identical multiplicands; see if we can find a common
-                power-of-two factor in non-power-of-two multiplies.  This
-                can help in multi-dimensional array access.  */
-             else if (TREE_CODE (arg01) == INTEGER_CST
-                      && TREE_CODE (arg11) == INTEGER_CST
-                      && TREE_INT_CST_HIGH (arg01) == 0
-                      && TREE_INT_CST_HIGH (arg11) == 0)
-               {
-                 HOST_WIDE_INT int01, int11, tmp;
-                 int01 = TREE_INT_CST_LOW (arg01);
-                 int11 = TREE_INT_CST_LOW (arg11);
-
-                 /* Move min of absolute values to int11.  */
-                 if ((int01 >= 0 ? int01 : -int01)
-                     < (int11 >= 0 ? int11 : -int11))
-                   {
-                     tmp = int01, int01 = int11, int11 = tmp;
-                     alt0 = arg00, arg00 = arg10, arg10 = alt0;
-                     alt0 = arg01, arg01 = arg11, arg11 = alt0;
-                   }
-
-                 if (exact_log2 (int11) > 0 && int01 % int11 == 0)
-                   {
-                     alt0 = fold_build2 (MULT_EXPR, type, arg00,
-                                         build_int_cst (NULL_TREE,
-                                                        int01 / int11));
-                     alt1 = arg10;
-                     same = arg11;
-                   }
-               }
-
-             if (same)
-               return fold_build2 (MULT_EXPR, type,
-                                   fold_build2 (PLUS_EXPR, type,
-                                                fold_convert (type, alt0),
-                                                fold_convert (type, alt1)),
-                                   fold_convert (type, same));
-           }
-
          /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
             of the array.  Loop optimizer sometimes produce this type of
             expressions.  */
@@ -7271,13 +8329,13 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg0, arg1);
              if (tem)
-               return fold_convert (type, fold (tem));
+               return fold_convert (type, tem);
            }
          else if (TREE_CODE (arg1) == ADDR_EXPR)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg1, arg0);
              if (tem)
-               return fold_convert (type, fold (tem));
+               return fold_convert (type, tem);
            }
        }
       else
@@ -7313,56 +8371,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            return fold_build2 (MULT_EXPR, type, arg0,
                                build_real (type, dconst2));
 
-         /* Convert x*c+x into x*(c+1).  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg0) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
-             && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
-           {
-             REAL_VALUE_TYPE c;
-
-             c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
-             real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold_build2 (MULT_EXPR, type, arg1,
-                                 build_real (type, c));
-           }
-
-         /* Convert x+x*c into x*(c+1).  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg1) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
-             && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
-           {
-             REAL_VALUE_TYPE c;
-
-             c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
-             real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold_build2 (MULT_EXPR, type, arg0,
-                                 build_real (type, c));
-           }
-
-         /* Convert x*c1+x*c2 into x*(c1+c2).  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg0) == MULT_EXPR
-             && TREE_CODE (arg1) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
-             && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
-             && operand_equal_p (TREE_OPERAND (arg0, 0),
-                                 TREE_OPERAND (arg1, 0), 0))
-           {
-             REAL_VALUE_TYPE c1, c2;
-
-             c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
-             c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
-             real_arithmetic (&c1, PLUS_EXPR, &c1, &c2);
-             return fold_build2 (MULT_EXPR, type,
-                                 TREE_OPERAND (arg0, 0),
-                                 build_real (type, c1));
-           }
           /* Convert a + (b*c + d*e) into (a + b*c) + d*e.  */
           if (flag_unsafe_math_optimizations
               && TREE_CODE (arg1) == PLUS_EXPR
@@ -7472,8 +8480,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
         don't associate floats at all, unless the user has specified
         -funsafe-math-optimizations.  */
 
-      if (! wins
-         && (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
+      if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
        {
          tree var0, con0, lit0, minus_lit0;
          tree var1, con1, lit1, minus_lit1;
@@ -7547,18 +8554,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            }
        }
 
-    binary:
-      if (wins)
-       t1 = const_binop (code, arg0, arg1, 0);
-      if (t1 != NULL_TREE)
-       {
-         /* The return value should always have
-            the same type as the original expression.  */
-         if (TREE_TYPE (t1) != type)
-           t1 = fold_convert (type, t1);
-
-         return t1;
-       }
       return NULL_TREE;
 
     case MINUS_EXPR:
@@ -7577,7 +8572,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       if (INTEGRAL_TYPE_P (type)
          && TREE_CODE (arg0) == NEGATE_EXPR
          && integer_onep (arg1))
-       return fold_build1 (BIT_NOT_EXPR, type, TREE_OPERAND (arg0, 0));
+       return fold_build1 (BIT_NOT_EXPR, type,
+                           fold_convert (type, TREE_OPERAND (arg0, 0)));
 
       /* Convert -1 - A to ~A.  */
       if (INTEGRAL_TYPE_P (type)
@@ -7586,7 +8582,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 
       if (! FLOAT_TYPE_P (type))
        {
-         if (! wins && integer_zerop (arg0))
+         if (integer_zerop (arg0))
            return negate_expr (fold_convert (type, arg1));
          if (integer_zerop (arg1))
            return non_lvalue (fold_convert (type, arg0));
@@ -7634,7 +8630,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       /* (ARG0 - ARG1) is the same as (-ARG1 + ARG0).  So check whether
         ARG0 is zero and X + ARG0 reduces to X, since that would mean
         (-ARG1 + ARG0) reduces to -ARG1.  */
-      else if (!wins && fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+      else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
        return negate_expr (fold_convert (type, arg1));
 
       /* Fold &x - &x.  This can happen from &x.foo - &x.
@@ -7648,7 +8644,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        return fold_convert (type, integer_zero_node);
 
       /* A - B -> A + (-B) if B is easily negatable.  */
-      if (!wins && negate_expr_p (arg1)
+      if (negate_expr_p (arg1)
          && ((FLOAT_TYPE_P (type)
                /* Avoid this transformation if B is a positive REAL_CST.  */
               && (TREE_CODE (arg1) != REAL_CST
@@ -7696,7 +8692,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        {
          tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1);
          if (tem)
-           return fold_convert (type, fold (tem));
+           return fold_convert (type, tem);
        }
 
       if (flag_unsafe_math_optimizations
@@ -7705,26 +8701,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && (tem = distribute_real_division (code, type, arg0, arg1)))
        return tem;
 
-      if (TREE_CODE (arg0) == MULT_EXPR
-         && TREE_CODE (arg1) == MULT_EXPR
+      /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the
+        same or one.  */
+      if ((TREE_CODE (arg0) == MULT_EXPR
+          || TREE_CODE (arg1) == MULT_EXPR)
          && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
-       {
-          /* (A * C) - (B * C) -> (A-B) * C.  */
-         if (operand_equal_p (TREE_OPERAND (arg0, 1),
-                              TREE_OPERAND (arg1, 1), 0))
-           return fold_build2 (MULT_EXPR, type,
-                               fold_build2 (MINUS_EXPR, type,
-                                            TREE_OPERAND (arg0, 0),
-                                            TREE_OPERAND (arg1, 0)),
-                               TREE_OPERAND (arg0, 1));
-          /* (A * C1) - (A * C2) -> A * (C1-C2).  */
-         if (operand_equal_p (TREE_OPERAND (arg0, 0),
-                              TREE_OPERAND (arg1, 0), 0))
-           return fold_build2 (MULT_EXPR, type,
-                               TREE_OPERAND (arg0, 0),
-                               fold_build2 (MINUS_EXPR, type,
-                                            TREE_OPERAND (arg0, 1),
-                                            TREE_OPERAND (arg1, 1)));
+        {
+         tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
+         if (tem)
+           return tem;
        }
 
       goto associate;
@@ -7989,11 +8974,78 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       if (TREE_CODE (arg1) == BIT_NOT_EXPR
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        {
-         t1 = build_int_cst (type, -1);
-         t1 = force_fit_type (t1, 0, false, false);
-         return omit_one_operand (type, t1, arg0);
+         t1 = build_int_cst (type, -1);
+         t1 = force_fit_type (t1, 0, false, false);
+         return omit_one_operand (type, t1, arg0);
+       }
+
+      /* Canonicalize (X & C1) | C2.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       {
+         unsigned HOST_WIDE_INT hi1, lo1, hi2, lo2, mlo, mhi;
+         int width = TYPE_PRECISION (type);
+         hi1 = TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1));
+         lo1 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
+         hi2 = TREE_INT_CST_HIGH (arg1);
+         lo2 = TREE_INT_CST_LOW (arg1);
+
+         /* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2).  */
+         if ((hi1 & hi2) == hi1 && (lo1 & lo2) == lo1)
+           return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 0));
+
+         if (width > HOST_BITS_PER_WIDE_INT)
+           {
+             mhi = (unsigned HOST_WIDE_INT) -1 
+                   >> (2 * HOST_BITS_PER_WIDE_INT - width);
+             mlo = -1;
+           }
+         else
+           {
+             mhi = 0;
+             mlo = (unsigned HOST_WIDE_INT) -1
+                   >> (HOST_BITS_PER_WIDE_INT - width);
+           }
+
+         /* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2.  */
+         if ((~(hi1 | hi2) & mhi) == 0 && (~(lo1 | lo2) & mlo) == 0)
+           return fold_build2 (BIT_IOR_EXPR, type,
+                               TREE_OPERAND (arg0, 0), arg1);
+
+         /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2.  */
+         hi1 &= mhi;
+         lo1 &= mlo;
+         if ((hi1 & ~hi2) != hi1 || (lo1 & ~lo2) != lo1)
+           return fold_build2 (BIT_IOR_EXPR, type,
+                               fold_build2 (BIT_AND_EXPR, type,
+                                            TREE_OPERAND (arg0, 0),
+                                            build_int_cst_wide (type,
+                                                                lo1 & ~lo2,
+                                                                hi1 & ~hi2)),
+                               arg1);
        }
 
+      /* (X & Y) | Y is (X, Y).  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
+       return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 0));
+      /* (X & Y) | X is (Y, X).  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
+       return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 1));
+      /* X | (X & Y) is (Y, X).  */
+      if (TREE_CODE (arg1) == BIT_AND_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 1)))
+       return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 1));
+      /* X | (Y & X) is (Y, X).  */
+      if (TREE_CODE (arg1) == BIT_AND_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+       return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 0));
+
       t1 = distribute_bit_expr (code, type, arg0, arg1);
       if (t1 != NULL_TREE)
        return t1;
@@ -8041,1216 +9093,1044 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          t1 = build_int_cst (type, -1);
          t1 = force_fit_type (t1, 0, false, false);
          return omit_one_operand (type, t1, arg0);
-       }
-
-      /* If we are XORing two BIT_AND_EXPR's, both of which are and'ing
-         with a constant, and the two constants have no bits in common,
-        we should treat this as a BIT_IOR_EXPR since this may produce more
-        simplifications.  */
-      if (TREE_CODE (arg0) == BIT_AND_EXPR
-         && TREE_CODE (arg1) == BIT_AND_EXPR
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
-         && integer_zerop (const_binop (BIT_AND_EXPR,
-                                        TREE_OPERAND (arg0, 1),
-                                        TREE_OPERAND (arg1, 1), 0)))
-       {
-         code = BIT_IOR_EXPR;
-         goto bit_ior;
-       }
-
-      /* Convert ~X ^ ~Y to X ^ Y.  */
-      if (TREE_CODE (arg0) == BIT_NOT_EXPR
-         && TREE_CODE (arg1) == BIT_NOT_EXPR)
-       return fold_build2 (code, type,
-                           fold_convert (type, TREE_OPERAND (arg0, 0)),
-                           fold_convert (type, TREE_OPERAND (arg1, 0)));
-
-      /* See if this can be simplified into a rotate first.  If that
-        is unsuccessful continue in the association code.  */
-      goto bit_rotate;
-
-    case BIT_AND_EXPR:
-      if (integer_all_onesp (arg1))
-       return non_lvalue (fold_convert (type, arg0));
-      if (integer_zerop (arg1))
-       return omit_one_operand (type, arg1, arg0);
-      if (operand_equal_p (arg0, arg1, 0))
-       return non_lvalue (fold_convert (type, arg0));
-
-      /* ~X & X is always zero.  */
-      if (TREE_CODE (arg0) == BIT_NOT_EXPR
-         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
-       return omit_one_operand (type, integer_zero_node, arg1);
-
-      /* X & ~X is always zero.  */
-      if (TREE_CODE (arg1) == BIT_NOT_EXPR
-         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
-       return omit_one_operand (type, integer_zero_node, arg0);
-
-      t1 = distribute_bit_expr (code, type, arg0, arg1);
-      if (t1 != NULL_TREE)
-       return t1;
-      /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char.  */
-      if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
-         && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
-       {
-         unsigned int prec
-           = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
-
-         if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_WIDE_INT
-             && (~TREE_INT_CST_LOW (arg1)
-                 & (((HOST_WIDE_INT) 1 << prec) - 1)) == 0)
-           return fold_convert (type, TREE_OPERAND (arg0, 0));
-       }
-
-      /* Convert (and (not arg0) (not arg1)) to (not (or (arg0) (arg1))).
-
-        This results in more efficient code for machines without a NOR
-        instruction.  Combine will canonicalize to the first form
-        which will allow use of NOR instructions provided by the
-        backend if they exist.  */
-      if (TREE_CODE (arg0) == BIT_NOT_EXPR
-         && TREE_CODE (arg1) == BIT_NOT_EXPR)
-       {
-         return fold_build1 (BIT_NOT_EXPR, type,
-                             build2 (BIT_IOR_EXPR, type,
-                                     TREE_OPERAND (arg0, 0),
-                                     TREE_OPERAND (arg1, 0)));
-       }
-
-      goto associate;
-
-    case RDIV_EXPR:
-      /* Don't touch a floating-point divide by zero unless the mode
-        of the constant can represent infinity.  */
-      if (TREE_CODE (arg1) == REAL_CST
-         && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1)))
-         && real_zerop (arg1))
-       return NULL_TREE;
-
-      /* (-A) / (-B) -> A / B  */
-      if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
-       return fold_build2 (RDIV_EXPR, type,
-                           TREE_OPERAND (arg0, 0),
-                           negate_expr (arg1));
-      if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
-       return fold_build2 (RDIV_EXPR, type,
-                           negate_expr (arg0),
-                           TREE_OPERAND (arg1, 0));
-
-      /* In IEEE floating point, x/1 is not equivalent to x for snans.  */
-      if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
-         && real_onep (arg1))
-       return non_lvalue (fold_convert (type, arg0));
-
-      /* In IEEE floating point, x/-1 is not equivalent to -x for snans.  */
-      if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
-         && real_minus_onep (arg1))
-       return non_lvalue (fold_convert (type, negate_expr (arg0)));
-
-      /* If ARG1 is a constant, we can convert this to a multiply by the
-        reciprocal.  This does not have the same rounding properties,
-        so only do this if -funsafe-math-optimizations.  We can actually
-        always safely do it if ARG1 is a power of two, but it's hard to
-        tell if it is or not in a portable manner.  */
-      if (TREE_CODE (arg1) == REAL_CST)
-       {
-         if (flag_unsafe_math_optimizations
-             && 0 != (tem = const_binop (code, build_real (type, dconst1),
-                                         arg1, 0)))
-           return fold_build2 (MULT_EXPR, type, arg0, tem);
-         /* Find the reciprocal if optimizing and the result is exact.  */
-         if (optimize)
-           {
-             REAL_VALUE_TYPE r;
-             r = TREE_REAL_CST (arg1);
-             if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
-               {
-                 tem = build_real (type, r);
-                 return fold_build2 (MULT_EXPR, type,
-                                     fold_convert (type, arg0), tem);
-               }
-           }
-       }
-      /* Convert A/B/C to A/(B*C).  */
-      if (flag_unsafe_math_optimizations
-         && TREE_CODE (arg0) == RDIV_EXPR)
-       return fold_build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
-                           fold_build2 (MULT_EXPR, type,
-                                        TREE_OPERAND (arg0, 1), arg1));
-
-      /* Convert A/(B/C) to (A/B)*C.  */
-      if (flag_unsafe_math_optimizations
-         && TREE_CODE (arg1) == RDIV_EXPR)
-       return fold_build2 (MULT_EXPR, type,
-                           fold_build2 (RDIV_EXPR, type, arg0,
-                                        TREE_OPERAND (arg1, 0)),
-                           TREE_OPERAND (arg1, 1));
-
-      /* Convert C1/(X*C2) into (C1/C2)/X.  */
-      if (flag_unsafe_math_optimizations
-         && TREE_CODE (arg1) == MULT_EXPR
-         && TREE_CODE (arg0) == REAL_CST
-         && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
-       {
-         tree tem = const_binop (RDIV_EXPR, arg0,
-                                 TREE_OPERAND (arg1, 1), 0);
-         if (tem)
-           return fold_build2 (RDIV_EXPR, type, tem,
-                               TREE_OPERAND (arg1, 0));
-       }
-
-      if (flag_unsafe_math_optimizations)
-       {
-         enum built_in_function fcode = builtin_mathfn_code (arg1);
-         /* Optimize x/expN(y) into x*expN(-y).  */
-         if (BUILTIN_EXPONENT_P (fcode))
-           {
-             tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
-             tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1)));
-             tree arglist = build_tree_list (NULL_TREE,
-                                             fold_convert (type, arg));
-             arg1 = build_function_call_expr (expfn, arglist);
-             return fold_build2 (MULT_EXPR, type, arg0, arg1);
-           }
-
-         /* Optimize x/pow(y,z) into x*pow(y,-z).  */
-         if (fcode == BUILT_IN_POW
-             || fcode == BUILT_IN_POWF
-             || fcode == BUILT_IN_POWL)
-           {
-             tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
-             tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
-             tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
-             tree neg11 = fold_convert (type, negate_expr (arg11));
-             tree arglist = tree_cons(NULL_TREE, arg10,
-                                      build_tree_list (NULL_TREE, neg11));
-             arg1 = build_function_call_expr (powfn, arglist);
-             return fold_build2 (MULT_EXPR, type, arg0, arg1);
-           }
-       }
-
-      if (flag_unsafe_math_optimizations)
-       {
-         enum built_in_function fcode0 = builtin_mathfn_code (arg0);
-         enum built_in_function fcode1 = builtin_mathfn_code (arg1);
-
-         /* Optimize sin(x)/cos(x) as tan(x).  */
-         if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS)
-              || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF)
-              || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL))
-             && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                 TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
-           {
-             tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
-
-             if (tanfn != NULL_TREE)
-               return build_function_call_expr (tanfn,
-                                                TREE_OPERAND (arg0, 1));
-           }
-
-         /* Optimize cos(x)/sin(x) as 1.0/tan(x).  */
-         if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN)
-              || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF)
-              || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL))
-             && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                 TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
-           {
-             tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
-
-             if (tanfn != NULL_TREE)
-               {
-                 tree tmp = TREE_OPERAND (arg0, 1);
-                 tmp = build_function_call_expr (tanfn, tmp);
-                 return fold_build2 (RDIV_EXPR, type,
-                                     build_real (type, dconst1), tmp);
-               }
-           }
-
-         /* Optimize pow(x,c)/x as pow(x,c-1).  */
-         if (fcode0 == BUILT_IN_POW
-             || fcode0 == BUILT_IN_POWF
-             || fcode0 == BUILT_IN_POWL)
-           {
-             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-             tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
-             if (TREE_CODE (arg01) == REAL_CST
-                 && ! TREE_CONSTANT_OVERFLOW (arg01)
-                 && operand_equal_p (arg1, arg00, 0))
-               {
-                 tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                 REAL_VALUE_TYPE c;
-                 tree arg, arglist;
+       }
 
-                 c = TREE_REAL_CST (arg01);
-                 real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
-                 arg = build_real (type, c);
-                 arglist = build_tree_list (NULL_TREE, arg);
-                 arglist = tree_cons (NULL_TREE, arg1, arglist);
-                 return build_function_call_expr (powfn, arglist);
-               }
-           }
+      /* If we are XORing two BIT_AND_EXPR's, both of which are and'ing
+         with a constant, and the two constants have no bits in common,
+        we should treat this as a BIT_IOR_EXPR since this may produce more
+        simplifications.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && TREE_CODE (arg1) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+         && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
+         && integer_zerop (const_binop (BIT_AND_EXPR,
+                                        TREE_OPERAND (arg0, 1),
+                                        TREE_OPERAND (arg1, 1), 0)))
+       {
+         code = BIT_IOR_EXPR;
+         goto bit_ior;
        }
-      goto binary;
 
-    case TRUNC_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case CEIL_DIV_EXPR:
-    case EXACT_DIV_EXPR:
-      if (integer_onep (arg1))
-       return non_lvalue (fold_convert (type, arg0));
-      if (integer_zerop (arg1))
-       return NULL_TREE;
-      /* X / -1 is -X.  */
-      if (!TYPE_UNSIGNED (type)
-         && TREE_CODE (arg1) == INTEGER_CST
-         && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
-         && TREE_INT_CST_HIGH (arg1) == -1)
-       return fold_convert (type, negate_expr (arg0));
+      /* (X | Y) ^ X -> Y & ~ X*/
+      if (TREE_CODE (arg0) == BIT_IOR_EXPR
+          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+        {
+         tree t2 = TREE_OPERAND (arg0, 1);
+         t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1),
+                           arg1);
+         t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2),
+                           fold_convert (type, t1));
+         return t1;
+       }
 
-      /* If arg0 is a multiple of arg1, then rewrite to the fastest div
-        operation, EXACT_DIV_EXPR.
+      /* (Y | X) ^ X -> Y & ~ X*/
+      if (TREE_CODE (arg0) == BIT_IOR_EXPR
+          && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
+        {
+         tree t2 = TREE_OPERAND (arg0, 0);
+         t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1),
+                           arg1);
+         t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2),
+                           fold_convert (type, t1));
+         return t1;
+       }
 
-        Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now.
-        At one time others generated faster code, it's not clear if they do
-        after the last round to changes to the DIV code in expmed.c.  */
-      if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR)
-         && multiple_of_p (type, arg0, arg1))
-       return fold_build2 (EXACT_DIV_EXPR, type, arg0, arg1);
+      /* X ^ (X | Y) -> Y & ~ X*/
+      if (TREE_CODE (arg1) == BIT_IOR_EXPR
+          && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
+        {
+         tree t2 = TREE_OPERAND (arg1, 1);
+         t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg0),
+                           arg0);
+         t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2),
+                           fold_convert (type, t1));
+         return t1;
+       }
 
-      if (TREE_CODE (arg1) == INTEGER_CST
-         && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
-       return fold_convert (type, tem);
+      /* X ^ (Y | X) -> Y & ~ X*/
+      if (TREE_CODE (arg1) == BIT_IOR_EXPR
+          && operand_equal_p (TREE_OPERAND (arg1, 1), arg0, 0))
+        {
+         tree t2 = TREE_OPERAND (arg1, 0);
+         t1 = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg0),
+                           arg0);
+         t1 = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, t2),
+                           fold_convert (type, t1));
+         return t1;
+       }
+       
+      /* Convert ~X ^ ~Y to X ^ Y.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+         && TREE_CODE (arg1) == BIT_NOT_EXPR)
+       return fold_build2 (code, type,
+                           fold_convert (type, TREE_OPERAND (arg0, 0)),
+                           fold_convert (type, TREE_OPERAND (arg1, 0)));
 
-      goto binary;
+      /* Fold (X & 1) ^ 1 as (X & 1) == 0.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && integer_onep (TREE_OPERAND (arg0, 1))
+         && integer_onep (arg1))
+       return fold_build2 (EQ_EXPR, type, arg0,
+                           build_int_cst (TREE_TYPE (arg0), 0));
 
-    case CEIL_MOD_EXPR:
-    case FLOOR_MOD_EXPR:
-    case ROUND_MOD_EXPR:
-    case TRUNC_MOD_EXPR:
-      /* X % 1 is always zero, but be sure to preserve any side
-        effects in X.  */
-      if (integer_onep (arg1))
-       return omit_one_operand (type, integer_zero_node, arg0);
+      /* Fold (X & Y) ^ Y as ~X & Y.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg0, 0));
+         return fold_build2 (BIT_AND_EXPR, type, 
+                             fold_build1 (BIT_NOT_EXPR, type, tem),
+                             fold_convert (type, arg1));
+       }
+      /* Fold (X & Y) ^ X as ~Y & X.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg0, 1));
+         return fold_build2 (BIT_AND_EXPR, type,
+                             fold_build1 (BIT_NOT_EXPR, type, tem),
+                             fold_convert (type, arg1));
+       }
+      /* Fold X ^ (X & Y) as X & ~Y.  */
+      if (TREE_CODE (arg1) == BIT_AND_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg1, 1));
+         return fold_build2 (BIT_AND_EXPR, type,
+                             fold_convert (type, arg0),
+                             fold_build1 (BIT_NOT_EXPR, type, tem));
+       }
+      /* Fold X ^ (Y & X) as ~Y & X.  */
+      if (TREE_CODE (arg1) == BIT_AND_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg1, 0));
+         return fold_build2 (BIT_AND_EXPR, type,
+                             fold_build1 (BIT_NOT_EXPR, type, tem),
+                             fold_convert (type, arg0));
+       }
 
-      /* X % 0, return X % 0 unchanged so that we can get the
-        proper warnings and errors.  */
+      /* See if this can be simplified into a rotate first.  If that
+        is unsuccessful continue in the association code.  */
+      goto bit_rotate;
+
+    case BIT_AND_EXPR:
+      if (integer_all_onesp (arg1))
+       return non_lvalue (fold_convert (type, arg0));
       if (integer_zerop (arg1))
-       return NULL_TREE;
+       return omit_one_operand (type, arg1, arg0);
+      if (operand_equal_p (arg0, arg1, 0))
+       return non_lvalue (fold_convert (type, arg0));
 
-      /* 0 % X is always zero, but be sure to preserve any side
-        effects in X.  Place this after checking for X == 0.  */
-      if (integer_zerop (arg0))
+      /* ~X & X is always zero.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
        return omit_one_operand (type, integer_zero_node, arg1);
 
-      /* X % -1 is zero.  */
-      if (!TYPE_UNSIGNED (type)
-         && TREE_CODE (arg1) == INTEGER_CST
-         && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
-         && TREE_INT_CST_HIGH (arg1) == -1)
+      /* X & ~X is always zero.  */
+      if (TREE_CODE (arg1) == BIT_NOT_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        return omit_one_operand (type, integer_zero_node, arg0);
 
-      /* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR,
-         i.e. "X % C" into "X & C2", if X and C are positive.  */
-      if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR)
-         && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0))
-         && integer_pow2p (arg1) && tree_int_cst_sgn (arg1) >= 0)
-       {
-         unsigned HOST_WIDE_INT high, low;
-         tree mask;
-         int l;
+      /* Canonicalize (X | C1) & C2 as (X & C2) | (C1 & C2).  */
+      if (TREE_CODE (arg0) == BIT_IOR_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       return fold_build2 (BIT_IOR_EXPR, type,
+                           fold_build2 (BIT_AND_EXPR, type,
+                                        TREE_OPERAND (arg0, 0), arg1),
+                           fold_build2 (BIT_AND_EXPR, type,
+                                        TREE_OPERAND (arg0, 1), arg1));
 
-         l = tree_log2 (arg1);
-         if (l >= HOST_BITS_PER_WIDE_INT)
-           {
-             high = ((unsigned HOST_WIDE_INT) 1
-                     << (l - HOST_BITS_PER_WIDE_INT)) - 1;
-             low = -1;
-           }
-         else
-           {
-             high = 0;
-             low = ((unsigned HOST_WIDE_INT) 1 << l) - 1;
-           }
+      /* (X | Y) & Y is (X, Y).  */
+      if (TREE_CODE (arg0) == BIT_IOR_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
+       return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 0));
+      /* (X | Y) & X is (Y, X).  */
+      if (TREE_CODE (arg0) == BIT_IOR_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
+       return omit_one_operand (type, arg1, TREE_OPERAND (arg0, 1));
+      /* X & (X | Y) is (Y, X).  */
+      if (TREE_CODE (arg1) == BIT_IOR_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 1)))
+       return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 1));
+      /* X & (Y | X) is (Y, X).  */
+      if (TREE_CODE (arg1) == BIT_IOR_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+       return omit_one_operand (type, arg0, TREE_OPERAND (arg1, 0));
+
+      /* Fold (X ^ 1) & 1 as (X & 1) == 0.  */
+      if (TREE_CODE (arg0) == BIT_XOR_EXPR
+         && integer_onep (TREE_OPERAND (arg0, 1))
+         && integer_onep (arg1))
+       {
+         tem = TREE_OPERAND (arg0, 0);
+         return fold_build2 (EQ_EXPR, type,
+                             fold_build2 (BIT_AND_EXPR, TREE_TYPE (tem), tem,
+                                          build_int_cst (TREE_TYPE (tem), 1)),
+                             build_int_cst (TREE_TYPE (tem), 0));
+       }
+      /* Fold ~X & 1 as (X & 1) == 0.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+         && integer_onep (arg1))
+       {
+         tem = TREE_OPERAND (arg0, 0);
+         return fold_build2 (EQ_EXPR, type,
+                             fold_build2 (BIT_AND_EXPR, TREE_TYPE (tem), tem,
+                                          build_int_cst (TREE_TYPE (tem), 1)),
+                             build_int_cst (TREE_TYPE (tem), 0));
+       }
 
-         mask = build_int_cst_wide (type, low, high);
+      /* Fold (X ^ Y) & Y as ~X & Y.  */
+      if (TREE_CODE (arg0) == BIT_XOR_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg0, 0));
+         return fold_build2 (BIT_AND_EXPR, type, 
+                             fold_build1 (BIT_NOT_EXPR, type, tem),
+                             fold_convert (type, arg1));
+       }
+      /* Fold (X ^ Y) & X as ~Y & X.  */
+      if (TREE_CODE (arg0) == BIT_XOR_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg0, 1));
+         return fold_build2 (BIT_AND_EXPR, type,
+                             fold_build1 (BIT_NOT_EXPR, type, tem),
+                             fold_convert (type, arg1));
+       }
+      /* Fold X & (X ^ Y) as X & ~Y.  */
+      if (TREE_CODE (arg1) == BIT_XOR_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg1, 1));
+         return fold_build2 (BIT_AND_EXPR, type,
+                             fold_convert (type, arg0),
+                             fold_build1 (BIT_NOT_EXPR, type, tem));
+       }
+      /* Fold X & (Y ^ X) as ~Y & X.  */
+      if (TREE_CODE (arg1) == BIT_XOR_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+       {
+         tem = fold_convert (type, TREE_OPERAND (arg1, 0));
          return fold_build2 (BIT_AND_EXPR, type,
-                             fold_convert (type, arg0), mask);
+                             fold_build1 (BIT_NOT_EXPR, type, tem),
+                             fold_convert (type, arg0));
        }
 
-      /* X % -C is the same as X % C.  */
-      if (code == TRUNC_MOD_EXPR
-         && !TYPE_UNSIGNED (type)
-         && TREE_CODE (arg1) == INTEGER_CST
-         && !TREE_CONSTANT_OVERFLOW (arg1)
-         && TREE_INT_CST_HIGH (arg1) < 0
-         && !flag_trapv
-         /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
-         && !sign_bit_p (arg1, arg1))
-       return fold_build2 (code, type, fold_convert (type, arg0),
-                           fold_convert (type, negate_expr (arg1)));
+      t1 = distribute_bit_expr (code, type, arg0, arg1);
+      if (t1 != NULL_TREE)
+       return t1;
+      /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char.  */
+      if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
+         && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+       {
+         unsigned int prec
+           = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
 
-      /* X % -Y is the same as X % Y.  */
-      if (code == TRUNC_MOD_EXPR
-         && !TYPE_UNSIGNED (type)
-         && TREE_CODE (arg1) == NEGATE_EXPR
-         && !flag_trapv)
-       return fold_build2 (code, type, fold_convert (type, arg0),
-                           fold_convert (type, TREE_OPERAND (arg1, 0)));
+         if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_WIDE_INT
+             && (~TREE_INT_CST_LOW (arg1)
+                 & (((HOST_WIDE_INT) 1 << prec) - 1)) == 0)
+           return fold_convert (type, TREE_OPERAND (arg0, 0));
+       }
 
-      if (TREE_CODE (arg1) == INTEGER_CST
-         && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
-       return fold_convert (type, tem);
+      /* Convert (and (not arg0) (not arg1)) to (not (or (arg0) (arg1))).
 
-      goto binary;
+        This results in more efficient code for machines without a NOR
+        instruction.  Combine will canonicalize to the first form
+        which will allow use of NOR instructions provided by the
+        backend if they exist.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+         && TREE_CODE (arg1) == BIT_NOT_EXPR)
+       {
+         return fold_build1 (BIT_NOT_EXPR, type,
+                             build2 (BIT_IOR_EXPR, type,
+                                     TREE_OPERAND (arg0, 0),
+                                     TREE_OPERAND (arg1, 0)));
+       }
 
-    case LROTATE_EXPR:
-    case RROTATE_EXPR:
-      if (integer_all_onesp (arg0))
-       return omit_one_operand (type, arg0, arg1);
-      goto shift;
+      goto associate;
 
-    case RSHIFT_EXPR:
-      /* Optimize -1 >> x for arithmetic right shifts.  */
-      if (integer_all_onesp (arg0) && !TYPE_UNSIGNED (type))
-       return omit_one_operand (type, arg0, arg1);
-      /* ... fall through ...  */
+    case RDIV_EXPR:
+      /* Don't touch a floating-point divide by zero unless the mode
+        of the constant can represent infinity.  */
+      if (TREE_CODE (arg1) == REAL_CST
+         && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1)))
+         && real_zerop (arg1))
+       return NULL_TREE;
 
-    case LSHIFT_EXPR:
-    shift:
-      if (integer_zerop (arg1))
-       return non_lvalue (fold_convert (type, arg0));
-      if (integer_zerop (arg0))
-       return omit_one_operand (type, arg0, arg1);
+      /* Optimize A / A to 1.0 if we don't care about
+        NaNs or Infinities.  Skip the transformation
+        for non-real operands.  */
+      if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg0))
+         && ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
+         && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg0)))
+         && operand_equal_p (arg0, arg1, 0))
+       {
+         tree r = build_real (TREE_TYPE (arg0), dconst1);
+
+         return omit_two_operands (type, r, arg0, arg1);
+       }
+
+      /* The complex version of the above A / A optimization.  */
+      if (COMPLEX_FLOAT_TYPE_P (TREE_TYPE (arg0))
+         && operand_equal_p (arg0, arg1, 0))
+       {
+         tree elem_type = TREE_TYPE (TREE_TYPE (arg0));
+         if (! HONOR_NANS (TYPE_MODE (elem_type))
+             && ! HONOR_INFINITIES (TYPE_MODE (elem_type)))
+           {
+             tree r = build_real (elem_type, dconst1);
+             /* omit_two_operands will call fold_convert for us.  */
+             return omit_two_operands (type, r, arg0, arg1);
+           }
+       }
+
+      /* (-A) / (-B) -> A / B  */
+      if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
+       return fold_build2 (RDIV_EXPR, type,
+                           TREE_OPERAND (arg0, 0),
+                           negate_expr (arg1));
+      if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
+       return fold_build2 (RDIV_EXPR, type,
+                           negate_expr (arg0),
+                           TREE_OPERAND (arg1, 0));
+
+      /* In IEEE floating point, x/1 is not equivalent to x for snans.  */
+      if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+         && real_onep (arg1))
+       return non_lvalue (fold_convert (type, arg0));
 
-      /* Since negative shift count is not well-defined,
-        don't try to compute it in the compiler.  */
-      if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
-       return NULL_TREE;
+      /* In IEEE floating point, x/-1 is not equivalent to -x for snans.  */
+      if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+         && real_minus_onep (arg1))
+       return non_lvalue (fold_convert (type, negate_expr (arg0)));
 
-      /* Turn (a OP c1) OP c2 into a OP (c1+c2).  */
-      if (TREE_CODE (arg0) == code && host_integerp (arg1, false)
-         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
-         && host_integerp (TREE_OPERAND (arg0, 1), false)
-         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+      /* If ARG1 is a constant, we can convert this to a multiply by the
+        reciprocal.  This does not have the same rounding properties,
+        so only do this if -funsafe-math-optimizations.  We can actually
+        always safely do it if ARG1 is a power of two, but it's hard to
+        tell if it is or not in a portable manner.  */
+      if (TREE_CODE (arg1) == REAL_CST)
        {
-         HOST_WIDE_INT low = (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
-                              + TREE_INT_CST_LOW (arg1));
-
-         /* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
-            being well defined.  */
-         if (low >= TYPE_PRECISION (type))
+         if (flag_unsafe_math_optimizations
+             && 0 != (tem = const_binop (code, build_real (type, dconst1),
+                                         arg1, 0)))
+           return fold_build2 (MULT_EXPR, type, arg0, tem);
+         /* Find the reciprocal if optimizing and the result is exact.  */
+         if (optimize)
            {
-             if (code == LROTATE_EXPR || code == RROTATE_EXPR)
-               low = low % TYPE_PRECISION (type);
-             else if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
-               return build_int_cst (type, 0);
-             else
-               low = TYPE_PRECISION (type) - 1;
+             REAL_VALUE_TYPE r;
+             r = TREE_REAL_CST (arg1);
+             if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
+               {
+                 tem = build_real (type, r);
+                 return fold_build2 (MULT_EXPR, type,
+                                     fold_convert (type, arg0), tem);
+               }
            }
+       }
+      /* Convert A/B/C to A/(B*C).  */
+      if (flag_unsafe_math_optimizations
+         && TREE_CODE (arg0) == RDIV_EXPR)
+       return fold_build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
+                           fold_build2 (MULT_EXPR, type,
+                                        TREE_OPERAND (arg0, 1), arg1));
 
-         return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
-                             build_int_cst (type, low));
+      /* Convert A/(B/C) to (A/B)*C.  */
+      if (flag_unsafe_math_optimizations
+         && TREE_CODE (arg1) == RDIV_EXPR)
+       return fold_build2 (MULT_EXPR, type,
+                           fold_build2 (RDIV_EXPR, type, arg0,
+                                        TREE_OPERAND (arg1, 0)),
+                           TREE_OPERAND (arg1, 1));
+
+      /* Convert C1/(X*C2) into (C1/C2)/X.  */
+      if (flag_unsafe_math_optimizations
+         && TREE_CODE (arg1) == MULT_EXPR
+         && TREE_CODE (arg0) == REAL_CST
+         && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
+       {
+         tree tem = const_binop (RDIV_EXPR, arg0,
+                                 TREE_OPERAND (arg1, 1), 0);
+         if (tem)
+           return fold_build2 (RDIV_EXPR, type, tem,
+                               TREE_OPERAND (arg1, 0));
        }
 
-      /* Transform (x >> c) << c into x & (-1<<c), or transform (x << c) >> c
-         into x & ((unsigned)-1 >> c) for unsigned types.  */
-      if (((code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR)
-           || (TYPE_UNSIGNED (type)
-              && code == RSHIFT_EXPR && TREE_CODE (arg0) == LSHIFT_EXPR))
-         && host_integerp (arg1, false)
-         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
-         && host_integerp (TREE_OPERAND (arg0, 1), false)
-         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+      if (flag_unsafe_math_optimizations)
        {
-         HOST_WIDE_INT low0 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
-         HOST_WIDE_INT low1 = TREE_INT_CST_LOW (arg1);
-         tree lshift;
-         tree arg00;
+         enum built_in_function fcode0 = builtin_mathfn_code (arg0);
+         enum built_in_function fcode1 = builtin_mathfn_code (arg1);
 
-         if (low0 == low1)
+         /* Optimize sin(x)/cos(x) as tan(x).  */
+         if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS)
+              || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF)
+              || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL))
+             && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
+                                 TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
            {
-             arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
-
-             lshift = build_int_cst (type, -1);
-             lshift = int_const_binop (code, lshift, arg1, 0);
+             tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
 
-             return fold_build2 (BIT_AND_EXPR, type, arg00, lshift);
+             if (tanfn != NULL_TREE)
+               return build_function_call_expr (tanfn,
+                                                TREE_OPERAND (arg0, 1));
            }
-       }
 
-      /* Rewrite an LROTATE_EXPR by a constant into an
-        RROTATE_EXPR by a new constant.  */
-      if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
-       {
-         tree tem = build_int_cst (NULL_TREE,
-                                   GET_MODE_BITSIZE (TYPE_MODE (type)));
-         tem = fold_convert (TREE_TYPE (arg1), tem);
-         tem = const_binop (MINUS_EXPR, tem, arg1, 0);
-         return fold_build2 (RROTATE_EXPR, type, arg0, tem);
-       }
+         /* Optimize cos(x)/sin(x) as 1.0/tan(x).  */
+         if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN)
+              || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF)
+              || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL))
+             && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
+                                 TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
+           {
+             tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
 
-      /* If we have a rotate of a bit operation with the rotate count and
-        the second operand of the bit operation both constant,
-        permute the two operations.  */
-      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
-         && (TREE_CODE (arg0) == BIT_AND_EXPR
-             || TREE_CODE (arg0) == BIT_IOR_EXPR
-             || TREE_CODE (arg0) == BIT_XOR_EXPR)
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       return fold_build2 (TREE_CODE (arg0), type,
-                           fold_build2 (code, type,
-                                        TREE_OPERAND (arg0, 0), arg1),
-                           fold_build2 (code, type,
-                                        TREE_OPERAND (arg0, 1), arg1));
+             if (tanfn != NULL_TREE)
+               {
+                 tree tmp = TREE_OPERAND (arg0, 1);
+                 tmp = build_function_call_expr (tanfn, tmp);
+                 return fold_build2 (RDIV_EXPR, type,
+                                     build_real (type, dconst1), tmp);
+               }
+           }
 
-      /* Two consecutive rotates adding up to the width of the mode can
-        be ignored.  */
-      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
-         && TREE_CODE (arg0) == RROTATE_EXPR
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-         && TREE_INT_CST_HIGH (arg1) == 0
-         && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
-         && ((TREE_INT_CST_LOW (arg1)
-              + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)))
-             == (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
-       return TREE_OPERAND (arg0, 0);
+         /* Optimize sin(x)/tan(x) as cos(x) if we don't care about
+            NaNs or Infinities.  */
+         if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_TAN)
+              || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_TANF)
+              || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_TANL)))
+           {
+             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+             tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1));
 
-      goto binary;
+             if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00)))
+                 && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00)))
+                 && operand_equal_p (arg00, arg01, 0))
+               {
+                 tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
 
-    case MIN_EXPR:
-      if (operand_equal_p (arg0, arg1, 0))
-       return omit_one_operand (type, arg0, arg1);
-      if (INTEGRAL_TYPE_P (type)
-         && operand_equal_p (arg1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST))
-       return omit_one_operand (type, arg1, arg0);
-      goto associate;
+                 if (cosfn != NULL_TREE)
+                   return build_function_call_expr (cosfn,
+                                                    TREE_OPERAND (arg0, 1));
+               }
+           }
 
-    case MAX_EXPR:
-      if (operand_equal_p (arg0, arg1, 0))
-       return omit_one_operand (type, arg0, arg1);
-      if (INTEGRAL_TYPE_P (type)
-         && TYPE_MAX_VALUE (type)
-         && operand_equal_p (arg1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST))
-       return omit_one_operand (type, arg1, arg0);
-      goto associate;
+         /* Optimize tan(x)/sin(x) as 1.0/cos(x) if we don't care about
+            NaNs or Infinities.  */
+         if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_SIN)
+              || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_SINF)
+              || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_SINL)))
+           {
+             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+             tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1));
 
-    case TRUTH_ANDIF_EXPR:
-      /* Note that the operands of this must be ints
-        and their values must be 0 or 1.
-        ("true" is a fixed value perhaps depending on the language.)  */
-      /* If first arg is constant zero, return it.  */
-      if (integer_zerop (arg0))
-       return fold_convert (type, arg0);
-    case TRUTH_AND_EXPR:
-      /* If either arg is constant true, drop it.  */
-      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
-       return non_lvalue (fold_convert (type, arg1));
-      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)
-         /* Preserve sequence points.  */
-         && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
-       return non_lvalue (fold_convert (type, arg0));
-      /* If second arg is constant zero, result is zero, but first arg
-        must be evaluated.  */
-      if (integer_zerop (arg1))
-       return omit_one_operand (type, arg1, arg0);
-      /* Likewise for first arg, but note that only the TRUTH_AND_EXPR
-        case will be handled here.  */
-      if (integer_zerop (arg0))
-       return omit_one_operand (type, arg0, arg1);
+             if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00)))
+                 && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00)))
+                 && operand_equal_p (arg00, arg01, 0))
+               {
+                 tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
 
-      /* !X && X is always false.  */
-      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
-         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
-       return omit_one_operand (type, integer_zero_node, arg1);
-      /* X && !X is always false.  */
-      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
-         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
-       return omit_one_operand (type, integer_zero_node, arg0);
+                 if (cosfn != NULL_TREE)
+                   {
+                     tree tmp = TREE_OPERAND (arg0, 1);
+                     tmp = build_function_call_expr (cosfn, tmp);
+                     return fold_build2 (RDIV_EXPR, type,
+                                         build_real (type, dconst1),
+                                         tmp);
+                   }
+               }
+           }
 
-      /* A < X && A + 1 > Y ==> A < X && A >= Y.  Normally A + 1 > Y
-        means A >= Y && A != MAX, but in this case we know that
-        A < X <= MAX.  */
+         /* Optimize pow(x,c)/x as pow(x,c-1).  */
+         if (fcode0 == BUILT_IN_POW
+             || fcode0 == BUILT_IN_POWF
+             || fcode0 == BUILT_IN_POWL)
+           {
+             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+             tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
+             if (TREE_CODE (arg01) == REAL_CST
+                 && ! TREE_CONSTANT_OVERFLOW (arg01)
+                 && operand_equal_p (arg1, arg00, 0))
+               {
+                 tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                 REAL_VALUE_TYPE c;
+                 tree arg, arglist;
 
-      if (!TREE_SIDE_EFFECTS (arg0)
-         && !TREE_SIDE_EFFECTS (arg1))
-       {
-         tem = fold_to_nonsharp_ineq_using_bound (arg0, arg1);
-         if (tem && !operand_equal_p (tem, arg0, 0))
-           return fold_build2 (code, type, tem, arg1);
+                 c = TREE_REAL_CST (arg01);
+                 real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
+                 arg = build_real (type, c);
+                 arglist = build_tree_list (NULL_TREE, arg);
+                 arglist = tree_cons (NULL_TREE, arg1, arglist);
+                 return build_function_call_expr (powfn, arglist);
+               }
+           }
+
+         /* Optimize x/expN(y) into x*expN(-y).  */
+         if (BUILTIN_EXPONENT_P (fcode1))
+           {
+             tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+             tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1)));
+             tree arglist = build_tree_list (NULL_TREE,
+                                             fold_convert (type, arg));
+             arg1 = build_function_call_expr (expfn, arglist);
+             return fold_build2 (MULT_EXPR, type, arg0, arg1);
+           }
 
-         tem = fold_to_nonsharp_ineq_using_bound (arg1, arg0);
-         if (tem && !operand_equal_p (tem, arg1, 0))
-           return fold_build2 (code, type, arg0, tem);
+         /* Optimize x/pow(y,z) into x*pow(y,-z).  */
+         if (fcode1 == BUILT_IN_POW
+             || fcode1 == BUILT_IN_POWF
+             || fcode1 == BUILT_IN_POWL)
+           {
+             tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+             tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+             tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
+             tree neg11 = fold_convert (type, negate_expr (arg11));
+             tree arglist = tree_cons(NULL_TREE, arg10,
+                                      build_tree_list (NULL_TREE, neg11));
+             arg1 = build_function_call_expr (powfn, arglist);
+             return fold_build2 (MULT_EXPR, type, arg0, arg1);
+           }
        }
+      return NULL_TREE;
 
-    truth_andor:
-      /* We only do these simplifications if we are optimizing.  */
-      if (!optimize)
-       return NULL_TREE;
-
-      /* Check for things like (A || B) && (A || C).  We can convert this
-        to A || (B && C).  Note that either operator can be any of the four
-        truth and/or operations and the transformation will still be
-        valid.   Also note that we only care about order for the
-        ANDIF and ORIF operators.  If B contains side effects, this
-        might change the truth-value of A.  */
-      if (TREE_CODE (arg0) == TREE_CODE (arg1)
-         && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR
-             || TREE_CODE (arg0) == TRUTH_ORIF_EXPR
-             || TREE_CODE (arg0) == TRUTH_AND_EXPR
-             || TREE_CODE (arg0) == TRUTH_OR_EXPR)
-         && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1)))
+    case TRUNC_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+      /* Simplify A / (B << N) where A and B are positive and B is
+        a power of 2, to A >> (N + log2(B)).  */
+      if (TREE_CODE (arg1) == LSHIFT_EXPR
+         && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0)))
        {
-         tree a00 = TREE_OPERAND (arg0, 0);
-         tree a01 = TREE_OPERAND (arg0, 1);
-         tree a10 = TREE_OPERAND (arg1, 0);
-         tree a11 = TREE_OPERAND (arg1, 1);
-         int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR
-                             || TREE_CODE (arg0) == TRUTH_AND_EXPR)
-                            && (code == TRUTH_AND_EXPR
-                                || code == TRUTH_OR_EXPR));
-
-         if (operand_equal_p (a00, a10, 0))
-           return fold_build2 (TREE_CODE (arg0), type, a00,
-                               fold_build2 (code, type, a01, a11));
-         else if (commutative && operand_equal_p (a00, a11, 0))
-           return fold_build2 (TREE_CODE (arg0), type, a00,
-                               fold_build2 (code, type, a01, a10));
-         else if (commutative && operand_equal_p (a01, a10, 0))
-           return fold_build2 (TREE_CODE (arg0), type, a01,
-                               fold_build2 (code, type, a00, a11));
-
-         /* This case if tricky because we must either have commutative
-            operators or else A10 must not have side-effects.  */
+         tree sval = TREE_OPERAND (arg1, 0);
+         if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0)
+           {
+             tree sh_cnt = TREE_OPERAND (arg1, 1);
+             unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval));
 
-         else if ((commutative || ! TREE_SIDE_EFFECTS (a10))
-                  && operand_equal_p (a01, a11, 0))
-           return fold_build2 (TREE_CODE (arg0), type,
-                               fold_build2 (code, type, a00, a10),
-                               a01);
+             sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt),
+                                   sh_cnt, build_int_cst (NULL_TREE, pow2));
+             return fold_build2 (RSHIFT_EXPR, type,
+                                 fold_convert (type, arg0), sh_cnt);
+           }
        }
+      /* Fall thru */
 
-      /* See if we can build a range comparison.  */
-      if (0 != (tem = fold_range_test (code, type, op0, op1)))
-       return tem;
-
-      /* Check for the possibility of merging component references.  If our
-        lhs is another similar operation, try to merge its rhs with our
-        rhs.  Then try to merge our lhs and rhs.  */
-      if (TREE_CODE (arg0) == code
-         && 0 != (tem = fold_truthop (code, type,
-                                      TREE_OPERAND (arg0, 1), arg1)))
-       return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
+    case ROUND_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      if (integer_onep (arg1))
+       return non_lvalue (fold_convert (type, arg0));
+      if (integer_zerop (arg1))
+       return NULL_TREE;
+      /* X / -1 is -X.  */
+      if (!TYPE_UNSIGNED (type)
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
+         && TREE_INT_CST_HIGH (arg1) == -1)
+       return fold_convert (type, negate_expr (arg0));
 
-      if ((tem = fold_truthop (code, type, arg0, arg1)) != 0)
-       return tem;
+      /* Convert -A / -B to A / B when the type is signed and overflow is
+        undefined.  */
+      if (!TYPE_UNSIGNED (type) && !flag_wrapv
+         && TREE_CODE (arg0) == NEGATE_EXPR
+         && negate_expr_p (arg1))
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                           negate_expr (arg1));
+      if (!TYPE_UNSIGNED (type) && !flag_wrapv
+         && TREE_CODE (arg1) == NEGATE_EXPR
+         && negate_expr_p (arg0))
+       return fold_build2 (code, type, negate_expr (arg0),
+                           TREE_OPERAND (arg1, 0));
 
-      return NULL_TREE;
+      /* If arg0 is a multiple of arg1, then rewrite to the fastest div
+        operation, EXACT_DIV_EXPR.
 
-    case TRUTH_ORIF_EXPR:
-      /* Note that the operands of this must be ints
-        and their values must be 0 or true.
-        ("true" is a fixed value perhaps depending on the language.)  */
-      /* If first arg is constant true, return it.  */
-      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
-       return fold_convert (type, arg0);
-    case TRUTH_OR_EXPR:
-      /* If either arg is constant zero, drop it.  */
-      if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0))
-       return non_lvalue (fold_convert (type, arg1));
-      if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1)
-         /* Preserve sequence points.  */
-         && (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
-       return non_lvalue (fold_convert (type, arg0));
-      /* If second arg is constant true, result is true, but we must
-        evaluate first arg.  */
-      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
-       return omit_one_operand (type, arg1, arg0);
-      /* Likewise for first arg, but note this only occurs here for
-        TRUTH_OR_EXPR.  */
-      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
-       return omit_one_operand (type, arg0, arg1);
+        Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now.
+        At one time others generated faster code, it's not clear if they do
+        after the last round to changes to the DIV code in expmed.c.  */
+      if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR)
+         && multiple_of_p (type, arg0, arg1))
+       return fold_build2 (EXACT_DIV_EXPR, type, arg0, arg1);
 
-      /* !X || X is always true.  */
-      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
-         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
-       return omit_one_operand (type, integer_one_node, arg1);
-      /* X || !X is always true.  */
-      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
-         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
-       return omit_one_operand (type, integer_one_node, arg0);
+      if (TREE_CODE (arg1) == INTEGER_CST
+         && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
+       return fold_convert (type, tem);
 
-      goto truth_andor;
+      return NULL_TREE;
 
-    case TRUTH_XOR_EXPR:
-      /* If the second arg is constant zero, drop it.  */
-      if (integer_zerop (arg1))
-       return non_lvalue (fold_convert (type, arg0));
-      /* If the second arg is constant true, this is a logical inversion.  */
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case TRUNC_MOD_EXPR:
+      /* X % 1 is always zero, but be sure to preserve any side
+        effects in X.  */
       if (integer_onep (arg1))
-       {
-         /* Only call invert_truthvalue if operand is a truth value.  */
-         if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
-           tem = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg0), arg0);
-         else
-           tem = invert_truthvalue (arg0);
-         return non_lvalue (fold_convert (type, tem));
-       }
-      /* Identical arguments cancel to zero.  */
-      if (operand_equal_p (arg0, arg1, 0))
        return omit_one_operand (type, integer_zero_node, arg0);
 
-      /* !X ^ X is always true.  */
-      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
-         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
-       return omit_one_operand (type, integer_one_node, arg1);
-
-      /* X ^ !X is always true.  */
-      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
-         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
-       return omit_one_operand (type, integer_one_node, arg0);
-
-      return NULL_TREE;
+      /* X % 0, return X % 0 unchanged so that we can get the
+        proper warnings and errors.  */
+      if (integer_zerop (arg1))
+       return NULL_TREE;
 
-    case EQ_EXPR:
-    case NE_EXPR:
-    case LT_EXPR:
-    case GT_EXPR:
-    case LE_EXPR:
-    case GE_EXPR:      
-      /* If one arg is a real or integer constant, put it last.  */
-      if (tree_swap_operands_p (arg0, arg1, true))
-       return fold_build2 (swap_tree_comparison (code), type, op1, op0);
-       
-      /* bool_var != 0 becomes bool_var. */
-      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
-          && code == NE_EXPR)
-        return non_lvalue (fold_convert (type, arg0));
-       
-      /* bool_var == 1 becomes bool_var. */
-      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
-          && code == EQ_EXPR)
-        return non_lvalue (fold_convert (type, arg0));
+      /* 0 % X is always zero, but be sure to preserve any side
+        effects in X.  Place this after checking for X == 0.  */
+      if (integer_zerop (arg0))
+       return omit_one_operand (type, integer_zero_node, arg1);
 
-      /* If this is an equality comparison of the address of a non-weak
-        object against zero, then we know the result.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (arg0) == ADDR_EXPR
-         && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
-         && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
-         && integer_zerop (arg1))
-       return constant_boolean_node (code != EQ_EXPR, type);
+      /* X % -1 is zero.  */
+      if (!TYPE_UNSIGNED (type)
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
+         && TREE_INT_CST_HIGH (arg1) == -1)
+       return omit_one_operand (type, integer_zero_node, arg0);
 
-      /* If this is an equality comparison of the address of two non-weak,
-        unaliased symbols neither of which are extern (since we do not
-        have access to attributes for externs), then we know the result.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (arg0) == ADDR_EXPR
-         && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
-         && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
-         && ! lookup_attribute ("alias",
-                                DECL_ATTRIBUTES (TREE_OPERAND (arg0, 0)))
-         && ! DECL_EXTERNAL (TREE_OPERAND (arg0, 0))
-         && TREE_CODE (arg1) == ADDR_EXPR
-         && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg1, 0))
-         && ! DECL_WEAK (TREE_OPERAND (arg1, 0))
-         && ! lookup_attribute ("alias",
-                                DECL_ATTRIBUTES (TREE_OPERAND (arg1, 0)))
-         && ! DECL_EXTERNAL (TREE_OPERAND (arg1, 0)))
+      /* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR,
+         i.e. "X % C" into "X & (C - 1)", if X and C are positive.  */
+      if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR)
+         && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0)))
        {
-         /* We know that we're looking at the address of two
-            non-weak, unaliased, static _DECL nodes.
+         tree c = arg1;
+         /* Also optimize A % (C << N)  where C is a power of 2,
+            to A & ((C << N) - 1).  */
+         if (TREE_CODE (arg1) == LSHIFT_EXPR)
+           c = TREE_OPERAND (arg1, 0);
 
-            It is both wasteful and incorrect to call operand_equal_p
-            to compare the two ADDR_EXPR nodes.  It is wasteful in that
-            all we need to do is test pointer equality for the arguments
-            to the two ADDR_EXPR nodes.  It is incorrect to use
-            operand_equal_p as that function is NOT equivalent to a
-            C equality test.  It can in fact return false for two
-            objects which would test as equal using the C equality
-            operator.  */
-         bool equal = TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0);
-         return constant_boolean_node (equal
-                                       ? code == EQ_EXPR : code != EQ_EXPR,
-                                       type);
+         if (integer_pow2p (c) && tree_int_cst_sgn (c) > 0)
+           {
+             tree mask = fold_build2 (MINUS_EXPR, TREE_TYPE (arg1),
+                                      arg1, integer_one_node);
+             return fold_build2 (BIT_AND_EXPR, type,
+                                 fold_convert (type, arg0),
+                                 fold_convert (type, mask));
+           }
        }
 
-      /* If this is a comparison of two exprs that look like an
-        ARRAY_REF of the same object, then we can fold this to a
-        comparison of the two offsets.  */
-      if (TREE_CODE_CLASS (code) == tcc_comparison)
-       {
-         tree base0, offset0, base1, offset1;
+      /* X % -C is the same as X % C.  */
+      if (code == TRUNC_MOD_EXPR
+         && !TYPE_UNSIGNED (type)
+         && TREE_CODE (arg1) == INTEGER_CST
+         && !TREE_CONSTANT_OVERFLOW (arg1)
+         && TREE_INT_CST_HIGH (arg1) < 0
+         && !flag_trapv
+         /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
+         && !sign_bit_p (arg1, arg1))
+       return fold_build2 (code, type, fold_convert (type, arg0),
+                           fold_convert (type, negate_expr (arg1)));
+
+      /* X % -Y is the same as X % Y.  */
+      if (code == TRUNC_MOD_EXPR
+         && !TYPE_UNSIGNED (type)
+         && TREE_CODE (arg1) == NEGATE_EXPR
+         && !flag_trapv)
+       return fold_build2 (code, type, fold_convert (type, arg0),
+                           fold_convert (type, TREE_OPERAND (arg1, 0)));
+
+      if (TREE_CODE (arg1) == INTEGER_CST
+         && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
+       return fold_convert (type, tem);
 
-         if (extract_array_ref (arg0, &base0, &offset0)
-             && extract_array_ref (arg1, &base1, &offset1)
-             && operand_equal_p (base0, base1, 0))
-           {
-             if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base0)))
-                 && integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base0)))))
-               offset0 = NULL_TREE;
-             if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base1)))
-                 && integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base1)))))
-               offset1 = NULL_TREE;
-             if (offset0 == NULL_TREE
-                 && offset1 == NULL_TREE)
-               {
-                 offset0 = integer_zero_node;
-                 offset1 = integer_zero_node;
-               }
-             else if (offset0 == NULL_TREE)
-               offset0 = build_int_cst (TREE_TYPE (offset1), 0);
-             else if (offset1 == NULL_TREE)
-               offset1 = build_int_cst (TREE_TYPE (offset0), 0);
+      return NULL_TREE;
 
-             if (TREE_TYPE (offset0) == TREE_TYPE (offset1))
-               return fold_build2 (code, type, offset0, offset1);
-           }
-       }
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      if (integer_all_onesp (arg0))
+       return omit_one_operand (type, arg0, arg1);
+      goto shift;
 
-      /* Transform comparisons of the form X +- C CMP X.  */
-      if ((code != EQ_EXPR && code != NE_EXPR)
-         && (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
-         && ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
-              && !HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
-             || (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-                 && !TYPE_UNSIGNED (TREE_TYPE (arg1))
-                 && !(flag_wrapv || flag_trapv))))
-       {
-         tree arg01 = TREE_OPERAND (arg0, 1);
-         enum tree_code code0 = TREE_CODE (arg0);
-         int is_positive;
+    case RSHIFT_EXPR:
+      /* Optimize -1 >> x for arithmetic right shifts.  */
+      if (integer_all_onesp (arg0) && !TYPE_UNSIGNED (type))
+       return omit_one_operand (type, arg0, arg1);
+      /* ... fall through ...  */
 
-         if (TREE_CODE (arg01) == REAL_CST)
-           is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1;
-         else
-           is_positive = tree_int_cst_sgn (arg01);
+    case LSHIFT_EXPR:
+    shift:
+      if (integer_zerop (arg1))
+       return non_lvalue (fold_convert (type, arg0));
+      if (integer_zerop (arg0))
+       return omit_one_operand (type, arg0, arg1);
 
-         /* (X - c) > X becomes false.  */
-         if (code == GT_EXPR
-             && ((code0 == MINUS_EXPR && is_positive >= 0)
-                 || (code0 == PLUS_EXPR && is_positive <= 0)))
-           return constant_boolean_node (0, type);
+      /* Since negative shift count is not well-defined,
+        don't try to compute it in the compiler.  */
+      if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
+       return NULL_TREE;
 
-         /* Likewise (X + c) < X becomes false.  */
-         if (code == LT_EXPR
-             && ((code0 == PLUS_EXPR && is_positive >= 0)
-                 || (code0 == MINUS_EXPR && is_positive <= 0)))
-           return constant_boolean_node (0, type);
+      /* Turn (a OP c1) OP c2 into a OP (c1+c2).  */
+      if (TREE_CODE (arg0) == code && host_integerp (arg1, false)
+         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
+         && host_integerp (TREE_OPERAND (arg0, 1), false)
+         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+       {
+         HOST_WIDE_INT low = (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
+                              + TREE_INT_CST_LOW (arg1));
 
-         /* Convert (X - c) <= X to true.  */
-         if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
-             && code == LE_EXPR
-             && ((code0 == MINUS_EXPR && is_positive >= 0)
-                 || (code0 == PLUS_EXPR && is_positive <= 0)))
-           return constant_boolean_node (1, type);
+         /* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
+            being well defined.  */
+         if (low >= TYPE_PRECISION (type))
+           {
+             if (code == LROTATE_EXPR || code == RROTATE_EXPR)
+               low = low % TYPE_PRECISION (type);
+             else if (TYPE_UNSIGNED (type) || code == LSHIFT_EXPR)
+               return build_int_cst (type, 0);
+             else
+               low = TYPE_PRECISION (type) - 1;
+           }
 
-         /* Convert (X + c) >= X to true.  */
-         if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
-             && code == GE_EXPR
-             && ((code0 == PLUS_EXPR && is_positive >= 0)
-                 || (code0 == MINUS_EXPR && is_positive <= 0)))
-           return constant_boolean_node (1, type);
+         return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                             build_int_cst (type, low));
+       }
 
-         if (TREE_CODE (arg01) == INTEGER_CST)
-           {
-             /* Convert X + c > X and X - c < X to true for integers.  */
-             if (code == GT_EXPR
-                 && ((code0 == PLUS_EXPR && is_positive > 0)
-                     || (code0 == MINUS_EXPR && is_positive < 0)))
-               return constant_boolean_node (1, type);
+      /* Transform (x >> c) << c into x & (-1<<c), or transform (x << c) >> c
+         into x & ((unsigned)-1 >> c) for unsigned types.  */
+      if (((code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR)
+           || (TYPE_UNSIGNED (type)
+              && code == RSHIFT_EXPR && TREE_CODE (arg0) == LSHIFT_EXPR))
+         && host_integerp (arg1, false)
+         && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
+         && host_integerp (TREE_OPERAND (arg0, 1), false)
+         && TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) < TYPE_PRECISION (type))
+       {
+         HOST_WIDE_INT low0 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
+         HOST_WIDE_INT low1 = TREE_INT_CST_LOW (arg1);
+         tree lshift;
+         tree arg00;
 
-             if (code == LT_EXPR
-                 && ((code0 == MINUS_EXPR && is_positive > 0)
-                     || (code0 == PLUS_EXPR && is_positive < 0)))
-               return constant_boolean_node (1, type);
+         if (low0 == low1)
+           {
+             arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
 
-             /* Convert X + c <= X and X - c >= X to false for integers.  */
-             if (code == LE_EXPR
-                 && ((code0 == PLUS_EXPR && is_positive > 0)
-                     || (code0 == MINUS_EXPR && is_positive < 0)))
-               return constant_boolean_node (0, type);
+             lshift = build_int_cst (type, -1);
+             lshift = int_const_binop (code, lshift, arg1, 0);
 
-             if (code == GE_EXPR
-                 && ((code0 == MINUS_EXPR && is_positive > 0)
-                     || (code0 == PLUS_EXPR && is_positive < 0)))
-               return constant_boolean_node (0, type);
+             return fold_build2 (BIT_AND_EXPR, type, arg00, lshift);
            }
        }
 
-      /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 +- C1.  */
-      if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-         && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-             && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
-             && !TYPE_UNSIGNED (TREE_TYPE (arg1))
-             && !(flag_wrapv || flag_trapv))
-         && (TREE_CODE (arg1) == INTEGER_CST
-             && !TREE_OVERFLOW (arg1)))
-       {
-         tree const1 = TREE_OPERAND (arg0, 1);
-         tree const2 = arg1;
-         tree variable = TREE_OPERAND (arg0, 0);
-         tree lhs;
-         int lhs_add;
-         lhs_add = TREE_CODE (arg0) != PLUS_EXPR;
-         
-         lhs = fold_build2 (lhs_add ? PLUS_EXPR : MINUS_EXPR,
-                            TREE_TYPE (arg1), const2, const1);
-         if (TREE_CODE (lhs) == TREE_CODE (arg1)
-             && (TREE_CODE (lhs) != INTEGER_CST
-                 || !TREE_OVERFLOW (lhs)))
-           return fold_build2 (code, type, variable, lhs);
+      /* Rewrite an LROTATE_EXPR by a constant into an
+        RROTATE_EXPR by a new constant.  */
+      if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
+       {
+         tree tem = build_int_cst (NULL_TREE,
+                                   GET_MODE_BITSIZE (TYPE_MODE (type)));
+         tem = fold_convert (TREE_TYPE (arg1), tem);
+         tem = const_binop (MINUS_EXPR, tem, arg1, 0);
+         return fold_build2 (RROTATE_EXPR, type, arg0, tem);
        }
 
-      if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
-       {
-         tree targ0 = strip_float_extensions (arg0);
-         tree targ1 = strip_float_extensions (arg1);
-         tree newtype = TREE_TYPE (targ0);
+      /* If we have a rotate of a bit operation with the rotate count and
+        the second operand of the bit operation both constant,
+        permute the two operations.  */
+      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
+         && (TREE_CODE (arg0) == BIT_AND_EXPR
+             || TREE_CODE (arg0) == BIT_IOR_EXPR
+             || TREE_CODE (arg0) == BIT_XOR_EXPR)
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       return fold_build2 (TREE_CODE (arg0), type,
+                           fold_build2 (code, type,
+                                        TREE_OPERAND (arg0, 0), arg1),
+                           fold_build2 (code, type,
+                                        TREE_OPERAND (arg0, 1), arg1));
 
-         if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
-           newtype = TREE_TYPE (targ1);
+      /* Two consecutive rotates adding up to the width of the mode can
+        be ignored.  */
+      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (arg0) == RROTATE_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+         && TREE_INT_CST_HIGH (arg1) == 0
+         && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
+         && ((TREE_INT_CST_LOW (arg1)
+              + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)))
+             == (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
+       return TREE_OPERAND (arg0, 0);
 
-         /* Fold (double)float1 CMP (double)float2 into float1 CMP float2.  */
-         if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
-           return fold_build2 (code, type, fold_convert (newtype, targ0),
-                               fold_convert (newtype, targ1));
+      return NULL_TREE;
 
-         /* (-a) CMP (-b) -> b CMP a  */
-         if (TREE_CODE (arg0) == NEGATE_EXPR
-             && TREE_CODE (arg1) == NEGATE_EXPR)
-           return fold_build2 (code, type, TREE_OPERAND (arg1, 0),
-                               TREE_OPERAND (arg0, 0));
+    case MIN_EXPR:
+      if (operand_equal_p (arg0, arg1, 0))
+       return omit_one_operand (type, arg0, arg1);
+      if (INTEGRAL_TYPE_P (type)
+         && operand_equal_p (arg1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST))
+       return omit_one_operand (type, arg1, arg0);
+      tem = fold_minmax (MIN_EXPR, type, arg0, arg1);
+      if (tem)
+       return tem;
+      goto associate;
 
-         if (TREE_CODE (arg1) == REAL_CST)
-         {
-           REAL_VALUE_TYPE cst;
-           cst = TREE_REAL_CST (arg1);
-
-           /* (-a) CMP CST -> a swap(CMP) (-CST)  */
-           if (TREE_CODE (arg0) == NEGATE_EXPR)
-             return
-               fold_build2 (swap_tree_comparison (code), type,
-                            TREE_OPERAND (arg0, 0),
-                            build_real (TREE_TYPE (arg1),
-                                        REAL_VALUE_NEGATE (cst)));
-
-           /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
-           /* a CMP (-0) -> a CMP 0  */
-           if (REAL_VALUE_MINUS_ZERO (cst))
-             return fold_build2 (code, type, arg0,
-                                 build_real (TREE_TYPE (arg1), dconst0));
-
-           /* x != NaN is always true, other ops are always false.  */
-           if (REAL_VALUE_ISNAN (cst)
-               && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
-             {
-               tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
-               return omit_one_operand (type, tem, arg0);
-             }
+    case MAX_EXPR:
+      if (operand_equal_p (arg0, arg1, 0))
+       return omit_one_operand (type, arg0, arg1);
+      if (INTEGRAL_TYPE_P (type)
+         && TYPE_MAX_VALUE (type)
+         && operand_equal_p (arg1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST))
+       return omit_one_operand (type, arg1, arg0);
+      tem = fold_minmax (MAX_EXPR, type, arg0, arg1);
+      if (tem)
+       return tem;
+      goto associate;
 
-           /* Fold comparisons against infinity.  */
-           if (REAL_VALUE_ISINF (cst))
-             {
-               tem = fold_inf_compare (code, type, arg0, arg1);
-               if (tem != NULL_TREE)
-                 return tem;
-             }
-         }
+    case TRUTH_ANDIF_EXPR:
+      /* Note that the operands of this must be ints
+        and their values must be 0 or 1.
+        ("true" is a fixed value perhaps depending on the language.)  */
+      /* If first arg is constant zero, return it.  */
+      if (integer_zerop (arg0))
+       return fold_convert (type, arg0);
+    case TRUTH_AND_EXPR:
+      /* If either arg is constant true, drop it.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+       return non_lvalue (fold_convert (type, arg1));
+      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)
+         /* Preserve sequence points.  */
+         && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
+       return non_lvalue (fold_convert (type, arg0));
+      /* If second arg is constant zero, result is zero, but first arg
+        must be evaluated.  */
+      if (integer_zerop (arg1))
+       return omit_one_operand (type, arg1, arg0);
+      /* Likewise for first arg, but note that only the TRUTH_AND_EXPR
+        case will be handled here.  */
+      if (integer_zerop (arg0))
+       return omit_one_operand (type, arg0, arg1);
 
-         /* If this is a comparison of a real constant with a PLUS_EXPR
-            or a MINUS_EXPR of a real constant, we can convert it into a
-            comparison with a revised real constant as long as no overflow
-            occurs when unsafe_math_optimizations are enabled.  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg1) == REAL_CST
-             && (TREE_CODE (arg0) == PLUS_EXPR
-                 || TREE_CODE (arg0) == MINUS_EXPR)
-             && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
-             && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
-                                         ? MINUS_EXPR : PLUS_EXPR,
-                                         arg1, TREE_OPERAND (arg0, 1), 0))
-             && ! TREE_CONSTANT_OVERFLOW (tem))
-           return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
-
-         /* Likewise, we can simplify a comparison of a real constant with
-            a MINUS_EXPR whose first operand is also a real constant, i.e.
-            (c1 - x) < c2 becomes x > c1-c2.  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg1) == REAL_CST
-             && TREE_CODE (arg0) == MINUS_EXPR
-             && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
-             && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
-                                         arg1, 0))
-             && ! TREE_CONSTANT_OVERFLOW (tem))
-           return fold_build2 (swap_tree_comparison (code), type,
-                               TREE_OPERAND (arg0, 1), tem);
+      /* !X && X is always false.  */
+      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+       return omit_one_operand (type, integer_zero_node, arg1);
+      /* X && !X is always false.  */
+      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+       return omit_one_operand (type, integer_zero_node, arg0);
 
-         /* Fold comparisons against built-in math functions.  */
-         if (TREE_CODE (arg1) == REAL_CST
-             && flag_unsafe_math_optimizations
-             && ! flag_errno_math)
-           {
-             enum built_in_function fcode = builtin_mathfn_code (arg0);
+      /* A < X && A + 1 > Y ==> A < X && A >= Y.  Normally A + 1 > Y
+        means A >= Y && A != MAX, but in this case we know that
+        A < X <= MAX.  */
 
-             if (fcode != END_BUILTINS)
-               {
-                 tem = fold_mathfn_compare (fcode, code, type, arg0, arg1);
-                 if (tem != NULL_TREE)
-                   return tem;
-               }
-           }
+      if (!TREE_SIDE_EFFECTS (arg0)
+         && !TREE_SIDE_EFFECTS (arg1))
+       {
+         tem = fold_to_nonsharp_ineq_using_bound (arg0, arg1);
+         if (tem && !operand_equal_p (tem, arg0, 0))
+           return fold_build2 (code, type, tem, arg1);
+
+         tem = fold_to_nonsharp_ineq_using_bound (arg1, arg0);
+         if (tem && !operand_equal_p (tem, arg1, 0))
+           return fold_build2 (code, type, arg0, tem);
        }
 
-      /* Convert foo++ == CONST into ++foo == CONST + INCR.  */
-      if (TREE_CONSTANT (arg1)
-         && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
-             || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
-         /* This optimization is invalid for ordered comparisons
-            if CONST+INCR overflows or if foo+incr might overflow.
-            This optimization is invalid for floating point due to rounding.
-            For pointer types we assume overflow doesn't happen.  */
-         && (POINTER_TYPE_P (TREE_TYPE (arg0))
-             || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
-                 && (code == EQ_EXPR || code == NE_EXPR))))
+    truth_andor:
+      /* We only do these simplifications if we are optimizing.  */
+      if (!optimize)
+       return NULL_TREE;
+
+      /* Check for things like (A || B) && (A || C).  We can convert this
+        to A || (B && C).  Note that either operator can be any of the four
+        truth and/or operations and the transformation will still be
+        valid.   Also note that we only care about order for the
+        ANDIF and ORIF operators.  If B contains side effects, this
+        might change the truth-value of A.  */
+      if (TREE_CODE (arg0) == TREE_CODE (arg1)
+         && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR
+             || TREE_CODE (arg0) == TRUTH_ORIF_EXPR
+             || TREE_CODE (arg0) == TRUTH_AND_EXPR
+             || TREE_CODE (arg0) == TRUTH_OR_EXPR)
+         && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1)))
        {
-         tree varop, newconst;
-
-         if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
-           {
-             newconst = fold_build2 (PLUS_EXPR, TREE_TYPE (arg0),
-                                     arg1, TREE_OPERAND (arg0, 1));
-             varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0),
-                             TREE_OPERAND (arg0, 0),
-                             TREE_OPERAND (arg0, 1));
-           }
-         else
-           {
-             newconst = fold_build2 (MINUS_EXPR, TREE_TYPE (arg0),
-                                     arg1, TREE_OPERAND (arg0, 1));
-             varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0),
-                             TREE_OPERAND (arg0, 0),
-                             TREE_OPERAND (arg0, 1));
-           }
+         tree a00 = TREE_OPERAND (arg0, 0);
+         tree a01 = TREE_OPERAND (arg0, 1);
+         tree a10 = TREE_OPERAND (arg1, 0);
+         tree a11 = TREE_OPERAND (arg1, 1);
+         int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR
+                             || TREE_CODE (arg0) == TRUTH_AND_EXPR)
+                            && (code == TRUTH_AND_EXPR
+                                || code == TRUTH_OR_EXPR));
 
+         if (operand_equal_p (a00, a10, 0))
+           return fold_build2 (TREE_CODE (arg0), type, a00,
+                               fold_build2 (code, type, a01, a11));
+         else if (commutative && operand_equal_p (a00, a11, 0))
+           return fold_build2 (TREE_CODE (arg0), type, a00,
+                               fold_build2 (code, type, a01, a10));
+         else if (commutative && operand_equal_p (a01, a10, 0))
+           return fold_build2 (TREE_CODE (arg0), type, a01,
+                               fold_build2 (code, type, a00, a11));
 
-         /* If VAROP is a reference to a bitfield, we must mask
-            the constant by the width of the field.  */
-         if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
-             && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
-             && host_integerp (DECL_SIZE (TREE_OPERAND
-                                          (TREE_OPERAND (varop, 0), 1)), 1))
-           {
-             tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
-             HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
-             tree folded_compare, shift;
-
-             /* First check whether the comparison would come out
-                always the same.  If we don't do that we would
-                change the meaning with the masking.  */
-             folded_compare = fold_build2 (code, type,
-                                           TREE_OPERAND (varop, 0), arg1);
-             if (integer_zerop (folded_compare)
-                 || integer_onep (folded_compare))
-               return omit_one_operand (type, folded_compare, varop);
-
-             shift = build_int_cst (NULL_TREE,
-                                    TYPE_PRECISION (TREE_TYPE (varop)) - size);
-             shift = fold_convert (TREE_TYPE (varop), shift);
-             newconst = fold_build2 (LSHIFT_EXPR, TREE_TYPE (varop),
-                                     newconst, shift);
-             newconst = fold_build2 (RSHIFT_EXPR, TREE_TYPE (varop),
-                                     newconst, shift);
-           }
+         /* This case if tricky because we must either have commutative
+            operators or else A10 must not have side-effects.  */
 
-         return fold_build2 (code, type, varop, newconst);
+         else if ((commutative || ! TREE_SIDE_EFFECTS (a10))
+                  && operand_equal_p (a01, a11, 0))
+           return fold_build2 (TREE_CODE (arg0), type,
+                               fold_build2 (code, type, a00, a10),
+                               a01);
        }
 
-      /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
-        This transformation affects the cases which are handled in later
-        optimizations involving comparisons with non-negative constants.  */
-      if (TREE_CODE (arg1) == INTEGER_CST
-         && TREE_CODE (arg0) != INTEGER_CST
-         && tree_int_cst_sgn (arg1) > 0)
-       {
-         switch (code)
-           {
-           case GE_EXPR:
-             arg1 = const_binop (MINUS_EXPR, arg1,
-                                 build_int_cst (TREE_TYPE (arg1), 1), 0);
-             return fold_build2 (GT_EXPR, type, arg0,
-                                 fold_convert (TREE_TYPE (arg0), arg1));
+      /* See if we can build a range comparison.  */
+      if (0 != (tem = fold_range_test (code, type, op0, op1)))
+       return tem;
 
-           case LT_EXPR:
-             arg1 = const_binop (MINUS_EXPR, arg1,
-                                 build_int_cst (TREE_TYPE (arg1), 1), 0);
-             return fold_build2 (LE_EXPR, type, arg0,
-                                 fold_convert (TREE_TYPE (arg0), arg1));
+      /* Check for the possibility of merging component references.  If our
+        lhs is another similar operation, try to merge its rhs with our
+        rhs.  Then try to merge our lhs and rhs.  */
+      if (TREE_CODE (arg0) == code
+         && 0 != (tem = fold_truthop (code, type,
+                                      TREE_OPERAND (arg0, 1), arg1)))
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
 
-           default:
-             break;
-           }
-       }
+      if ((tem = fold_truthop (code, type, arg0, arg1)) != 0)
+       return tem;
 
-      /* Comparisons with the highest or lowest possible integer of
-        the specified size will have known values.  */
-      {
-       int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg1)));
+      return NULL_TREE;
 
-       if (TREE_CODE (arg1) == INTEGER_CST
-           && ! TREE_CONSTANT_OVERFLOW (arg1)
-           && width <= 2 * HOST_BITS_PER_WIDE_INT
-           && (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
-               || POINTER_TYPE_P (TREE_TYPE (arg1))))
-         {
-           HOST_WIDE_INT signed_max_hi;
-           unsigned HOST_WIDE_INT signed_max_lo;
-           unsigned HOST_WIDE_INT max_hi, max_lo, min_hi, min_lo;
+    case TRUTH_ORIF_EXPR:
+      /* Note that the operands of this must be ints
+        and their values must be 0 or true.
+        ("true" is a fixed value perhaps depending on the language.)  */
+      /* If first arg is constant true, return it.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+       return fold_convert (type, arg0);
+    case TRUTH_OR_EXPR:
+      /* If either arg is constant zero, drop it.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0))
+       return non_lvalue (fold_convert (type, arg1));
+      if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1)
+         /* Preserve sequence points.  */
+         && (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
+       return non_lvalue (fold_convert (type, arg0));
+      /* If second arg is constant true, result is true, but we must
+        evaluate first arg.  */
+      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
+       return omit_one_operand (type, arg1, arg0);
+      /* Likewise for first arg, but note this only occurs here for
+        TRUTH_OR_EXPR.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+       return omit_one_operand (type, arg0, arg1);
 
-           if (width <= HOST_BITS_PER_WIDE_INT)
-             {
-               signed_max_lo = ((unsigned HOST_WIDE_INT) 1 << (width - 1))
-                               - 1;
-               signed_max_hi = 0;
-               max_hi = 0;
+      /* !X || X is always true.  */
+      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+       return omit_one_operand (type, integer_one_node, arg1);
+      /* X || !X is always true.  */
+      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+       return omit_one_operand (type, integer_one_node, arg0);
 
-               if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
-                 {
-                   max_lo = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
-                   min_lo = 0;
-                   min_hi = 0;
-                 }
-               else
-                 {
-                   max_lo = signed_max_lo;
-                   min_lo = ((unsigned HOST_WIDE_INT) -1 << (width - 1));
-                   min_hi = -1;
-                 }
-             }
-           else
-             {
-               width -= HOST_BITS_PER_WIDE_INT;
-               signed_max_lo = -1;
-               signed_max_hi = ((unsigned HOST_WIDE_INT) 1 << (width - 1))
-                               - 1;
-               max_lo = -1;
-               min_lo = 0;
+      goto truth_andor;
 
-               if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
-                 {
-                   max_hi = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
-                   min_hi = 0;
-                 }
-               else
-                 {
-                   max_hi = signed_max_hi;
-                   min_hi = ((unsigned HOST_WIDE_INT) -1 << (width - 1));
-                 }
-             }
+    case TRUTH_XOR_EXPR:
+      /* If the second arg is constant zero, drop it.  */
+      if (integer_zerop (arg1))
+       return non_lvalue (fold_convert (type, arg0));
+      /* If the second arg is constant true, this is a logical inversion.  */
+      if (integer_onep (arg1))
+       {
+         /* Only call invert_truthvalue if operand is a truth value.  */
+         if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
+           tem = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg0), arg0);
+         else
+           tem = invert_truthvalue (arg0);
+         return non_lvalue (fold_convert (type, tem));
+       }
+      /* Identical arguments cancel to zero.  */
+      if (operand_equal_p (arg0, arg1, 0))
+       return omit_one_operand (type, integer_zero_node, arg0);
 
-           if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1) == max_hi
-               && TREE_INT_CST_LOW (arg1) == max_lo)
-             switch (code)
-               {
-               case GT_EXPR:
-                 return omit_one_operand (type, integer_zero_node, arg0);
+      /* !X ^ X is always true.  */
+      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+       return omit_one_operand (type, integer_one_node, arg1);
 
-               case GE_EXPR:
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+      /* X ^ !X is always true.  */
+      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
+         && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+       return omit_one_operand (type, integer_one_node, arg0);
 
-               case LE_EXPR:
-                 return omit_one_operand (type, integer_one_node, arg0);
+      return NULL_TREE;
 
-               case LT_EXPR:
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+    case EQ_EXPR:
+    case NE_EXPR:
+      tem = fold_comparison (code, type, op0, op1);
+      if (tem != NULL_TREE)
+       return tem;
 
-               /* The GE_EXPR and LT_EXPR cases above are not normally
-                  reached because of previous transformations.  */
+      /* bool_var != 0 becomes bool_var. */
+      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
+          && code == NE_EXPR)
+        return non_lvalue (fold_convert (type, arg0));
 
-               default:
-                 break;
-               }
-           else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
-                    == max_hi
-                    && TREE_INT_CST_LOW (arg1) == max_lo - 1)
-             switch (code)
-               {
-               case GT_EXPR:
-                 arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
-               case LE_EXPR:
-                 arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
-               default:
-                 break;
-               }
-           else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
-                    == min_hi
-                    && TREE_INT_CST_LOW (arg1) == min_lo)
-             switch (code)
-               {
-               case LT_EXPR:
-                 return omit_one_operand (type, integer_zero_node, arg0);
+      /* bool_var == 1 becomes bool_var. */
+      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
+          && code == EQ_EXPR)
+        return non_lvalue (fold_convert (type, arg0));
 
-               case LE_EXPR:
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+      /* bool_var != 1 becomes !bool_var. */
+      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
+          && code == NE_EXPR)
+        return fold_build1 (TRUTH_NOT_EXPR, type, arg0);
 
-               case GE_EXPR:
-                 return omit_one_operand (type, integer_one_node, arg0);
+      /* bool_var == 0 becomes !bool_var. */
+      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
+          && code == EQ_EXPR)
+        return fold_build1 (TRUTH_NOT_EXPR, type, arg0);
 
-               case GT_EXPR:
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+      /*  ~a != C becomes a != ~C where C is a constant.  Likewise for ==.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST)
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                           fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), 
+                                        arg1));
+
+      /* If this is an equality comparison of the address of a non-weak
+        object against zero, then we know the result.  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+         && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
+         && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
+         && integer_zerop (arg1))
+       return constant_boolean_node (code != EQ_EXPR, type);
 
-               default:
-                 break;
-               }
-           else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
-                    == min_hi
-                    && TREE_INT_CST_LOW (arg1) == min_lo + 1)
-             switch (code)
-               {
-               case GE_EXPR:
-                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
-               case LT_EXPR:
-                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
-               default:
-                 break;
-               }
+      /* If this is an equality comparison of the address of two non-weak,
+        unaliased symbols neither of which are extern (since we do not
+        have access to attributes for externs), then we know the result.  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+         && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
+         && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
+         && ! lookup_attribute ("alias",
+                                DECL_ATTRIBUTES (TREE_OPERAND (arg0, 0)))
+         && ! DECL_EXTERNAL (TREE_OPERAND (arg0, 0))
+         && TREE_CODE (arg1) == ADDR_EXPR
+         && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg1, 0))
+         && ! DECL_WEAK (TREE_OPERAND (arg1, 0))
+         && ! lookup_attribute ("alias",
+                                DECL_ATTRIBUTES (TREE_OPERAND (arg1, 0)))
+         && ! DECL_EXTERNAL (TREE_OPERAND (arg1, 0)))
+       {
+         /* We know that we're looking at the address of two
+            non-weak, unaliased, static _DECL nodes.
 
-           else if (!in_gimple_form
-                    && TREE_INT_CST_HIGH (arg1) == signed_max_hi
-                    && TREE_INT_CST_LOW (arg1) == signed_max_lo
-                    && TYPE_UNSIGNED (TREE_TYPE (arg1))
-                    /* signed_type does not work on pointer types.  */
-                    && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
-             {
-               /* The following case also applies to X < signed_max+1
-                  and X >= signed_max+1 because previous transformations.  */
-               if (code == LE_EXPR || code == GT_EXPR)
-                 {
-                   tree st0, st1;
-                   st0 = lang_hooks.types.signed_type (TREE_TYPE (arg0));
-                   st1 = lang_hooks.types.signed_type (TREE_TYPE (arg1));
-                   return fold
-                     (build2 (code == LE_EXPR ? GE_EXPR: LT_EXPR,
-                              type, fold_convert (st0, arg0),
-                              fold_convert (st1, integer_zero_node)));
-                 }
-             }
-         }
-      }
+            It is both wasteful and incorrect to call operand_equal_p
+            to compare the two ADDR_EXPR nodes.  It is wasteful in that
+            all we need to do is test pointer equality for the arguments
+            to the two ADDR_EXPR nodes.  It is incorrect to use
+            operand_equal_p as that function is NOT equivalent to a
+            C equality test.  It can in fact return false for two
+            objects which would test as equal using the C equality
+            operator.  */
+         bool equal = TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0);
+         return constant_boolean_node (equal
+                                       ? code == EQ_EXPR : code != EQ_EXPR,
+                                       type);
+       }
 
       /* If this is an EQ or NE comparison of a constant with a PLUS_EXPR or
         a MINUS_EXPR of a constant, we can convert it into a comparison with
         a revised constant as long as no overflow occurs.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (arg1) == INTEGER_CST
+      if (TREE_CODE (arg1) == INTEGER_CST
          && (TREE_CODE (arg0) == PLUS_EXPR
              || TREE_CODE (arg0) == MINUS_EXPR)
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
@@ -9261,87 +10141,23 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
 
       /* Similarly for a NEGATE_EXPR.  */
-      else if ((code == EQ_EXPR || code == NE_EXPR)
-              && TREE_CODE (arg0) == NEGATE_EXPR
-              && TREE_CODE (arg1) == INTEGER_CST
-              && 0 != (tem = negate_expr (arg1))
-              && TREE_CODE (tem) == INTEGER_CST
-              && ! TREE_CONSTANT_OVERFLOW (tem))
+      if (TREE_CODE (arg0) == NEGATE_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST
+         && 0 != (tem = negate_expr (arg1))
+         && TREE_CODE (tem) == INTEGER_CST
+         && ! TREE_CONSTANT_OVERFLOW (tem))
        return fold_build2 (code, type, TREE_OPERAND (arg0, 0), tem);
 
       /* If we have X - Y == 0, we can convert that to X == Y and similarly
         for !=.  Don't do this for ordered comparisons due to overflow.  */
-      else if ((code == NE_EXPR || code == EQ_EXPR)
-              && integer_zerop (arg1) && TREE_CODE (arg0) == MINUS_EXPR)
+      if (TREE_CODE (arg0) == MINUS_EXPR
+         && integer_zerop (arg1))
        return fold_build2 (code, type,
                            TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
 
-      else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
-              && (TREE_CODE (arg0) == NOP_EXPR
-                  || TREE_CODE (arg0) == CONVERT_EXPR))
-       {
-         /* If we are widening one operand of an integer comparison,
-            see if the other operand is similarly being widened.  Perhaps we
-            can do the comparison in the narrower type.  */
-         tem = fold_widened_comparison (code, type, arg0, arg1);
-         if (tem)
-           return tem;
-
-         /* Or if we are changing signedness.  */
-         tem = fold_sign_changed_comparison (code, type, arg0, arg1);
-         if (tem)
-           return tem;
-       }
-
-      /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a
-        constant, we can simplify it.  */
-      else if (TREE_CODE (arg1) == INTEGER_CST
-              && (TREE_CODE (arg0) == MIN_EXPR
-                  || TREE_CODE (arg0) == MAX_EXPR)
-              && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       {
-         tem = optimize_minmax_comparison (code, type, op0, op1);
-         if (tem)
-           return tem;
-
-         return NULL_TREE;
-       }
-
-      /* If we are comparing an ABS_EXPR with a constant, we can
-        convert all the cases into explicit comparisons, but they may
-        well not be faster than doing the ABS and one comparison.
-        But ABS (X) <= C is a range comparison, which becomes a subtraction
-        and a comparison, and is probably faster.  */
-      else if (code == LE_EXPR && TREE_CODE (arg1) == INTEGER_CST
-              && TREE_CODE (arg0) == ABS_EXPR
-              && ! TREE_SIDE_EFFECTS (arg0)
-              && (0 != (tem = negate_expr (arg1)))
-              && TREE_CODE (tem) == INTEGER_CST
-              && ! TREE_CONSTANT_OVERFLOW (tem))
-       return fold_build2 (TRUTH_ANDIF_EXPR, type,
-                           build2 (GE_EXPR, type,
-                                   TREE_OPERAND (arg0, 0), tem),
-                           build2 (LE_EXPR, type,
-                                   TREE_OPERAND (arg0, 0), arg1));
-
-      /* Convert ABS_EXPR<x> >= 0 to true.  */
-      else if (code == GE_EXPR
-              && tree_expr_nonnegative_p (arg0)
-              && (integer_zerop (arg1)
-                  || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
-                       && real_zerop (arg1))))
-       return omit_one_operand (type, integer_one_node, arg0);
-
-      /* Convert ABS_EXPR<x> < 0 to false.  */
-      else if (code == LT_EXPR
-              && tree_expr_nonnegative_p (arg0)
-              && (integer_zerop (arg1) || real_zerop (arg1)))
-       return omit_one_operand (type, integer_zero_node, arg0);
-
       /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0.  */
-      else if ((code == EQ_EXPR || code == NE_EXPR)
-              && TREE_CODE (arg0) == ABS_EXPR
-              && (integer_zerop (arg1) || real_zerop (arg1)))
+      if (TREE_CODE (arg0) == ABS_EXPR
+         && (integer_zerop (arg1) || real_zerop (arg1)))
        return fold_build2 (code, type, TREE_OPERAND (arg0, 0), arg1);
 
       /* If this is an EQ or NE comparison with zero and ARG0 is
@@ -9349,8 +10165,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
         two operations, but the latter can be done in one less insn
         on machines that have only two-operand insns or on which a
         constant cannot be the first operand.  */
-      if (integer_zerop (arg1) && (code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (arg0) == BIT_AND_EXPR)
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && integer_zerop (arg1))
        {
          tree arg00 = TREE_OPERAND (arg0, 0);
          tree arg01 = TREE_OPERAND (arg0, 1);
@@ -9379,8 +10195,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       /* If this is an NE or EQ comparison of zero against the result of a
         signed MOD operation whose second operand is a power of 2, make
         the MOD operation unsigned since it is simpler and equivalent.  */
-      if ((code == NE_EXPR || code == EQ_EXPR)
-         && integer_zerop (arg1)
+      if (integer_zerop (arg1)
          && !TYPE_UNSIGNED (TREE_TYPE (arg0))
          && (TREE_CODE (arg0) == TRUNC_MOD_EXPR
              || TREE_CODE (arg0) == CEIL_MOD_EXPR
@@ -9399,17 +10214,63 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                              fold_convert (newtype, arg1));
        }
 
+      /* Fold ((X >> C1) & C2) == 0 and ((X >> C1) & C2) != 0 where
+        C1 is a valid shift constant, and C2 is a power of two, i.e.
+        a single bit.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == RSHIFT_EXPR
+         && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1))
+            == INTEGER_CST
+         && integer_pow2p (TREE_OPERAND (arg0, 1))
+         && integer_zerop (arg1))
+       {
+         tree itype = TREE_TYPE (arg0);
+         unsigned HOST_WIDE_INT prec = TYPE_PRECISION (itype);
+         tree arg001 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 1);
+
+         /* Check for a valid shift count.  */
+         if (TREE_INT_CST_HIGH (arg001) == 0
+             && TREE_INT_CST_LOW (arg001) < prec)
+           {
+             tree arg01 = TREE_OPERAND (arg0, 1);
+             tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+             unsigned HOST_WIDE_INT log2 = tree_log2 (arg01);
+             /* If (C2 << C1) doesn't overflow, then ((X >> C1) & C2) != 0
+                can be rewritten as (X & (C2 << C1)) != 0.  */
+             if ((log2 + TREE_INT_CST_LOW (arg01)) < prec)
+               {
+                 tem = fold_build2 (LSHIFT_EXPR, itype, arg01, arg001);
+                 tem = fold_build2 (BIT_AND_EXPR, itype, arg000, tem);
+                 return fold_build2 (code, type, tem, arg1);
+               }
+             /* Otherwise, for signed (arithmetic) shifts,
+                ((X >> C1) & C2) != 0 is rewritten as X < 0, and
+                ((X >> C1) & C2) == 0 is rewritten as X >= 0.  */
+             else if (!TYPE_UNSIGNED (itype))
+               return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR, type,
+                                   arg000, build_int_cst (itype, 0));
+             /* Otherwise, of unsigned (logical) shifts,
+                ((X >> C1) & C2) != 0 is rewritten as (X,false), and
+                ((X >> C1) & C2) == 0 is rewritten as (X,true).  */
+             else
+               return omit_one_operand (type,
+                                        code == EQ_EXPR ? integer_one_node
+                                                        : integer_zero_node,
+                                        arg000);
+           }
+       }
+
       /* If this is an NE comparison of zero with an AND of one, remove the
         comparison since the AND will give the correct value.  */
-      if (code == NE_EXPR && integer_zerop (arg1)
+      if (code == NE_EXPR
+         && integer_zerop (arg1)
          && TREE_CODE (arg0) == BIT_AND_EXPR
          && integer_onep (TREE_OPERAND (arg0, 1)))
        return fold_convert (type, arg0);
 
       /* If we have (A & C) == C where C is a power of 2, convert this into
         (A & C) != 0.  Similarly for NE_EXPR.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (arg0) == BIT_AND_EXPR
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
          && integer_pow2p (TREE_OPERAND (arg0, 1))
          && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
        return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
@@ -9424,8 +10285,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 
       /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
         Similarly for NE_EXPR.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (arg0) == BIT_AND_EXPR
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
          && TREE_CODE (arg1) == INTEGER_CST
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
        {
@@ -9439,267 +10299,495 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            return omit_one_operand (type, rslt, arg0);
        }
 
-      /* If we have (A | C) == D where C & ~D != 0, convert this into 0.
-        Similarly for NE_EXPR.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (arg0) == BIT_IOR_EXPR
-         && TREE_CODE (arg1) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       {
-         tree notd = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1);
-         tree candnotd = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
-                                      TREE_OPERAND (arg0, 1), notd);
-         tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
-         if (integer_nonzerop (candnotd))
-           return omit_one_operand (type, rslt, arg0);
-       }
+      /* If we have (A | C) == D where C & ~D != 0, convert this into 0.
+        Similarly for NE_EXPR.  */
+      if (TREE_CODE (arg0) == BIT_IOR_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       {
+         tree notd = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1);
+         tree candnotd = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                                      TREE_OPERAND (arg0, 1), notd);
+         tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
+         if (integer_nonzerop (candnotd))
+           return omit_one_operand (type, rslt, arg0);
+       }
+
+      /* If this is a comparison of a field, we may be able to simplify it.  */
+      if (((TREE_CODE (arg0) == COMPONENT_REF
+           && lang_hooks.can_use_bit_fields_p ())
+          || TREE_CODE (arg0) == BIT_FIELD_REF)
+         /* Handle the constant case even without -O
+            to make sure the warnings are given.  */
+         && (optimize || TREE_CODE (arg1) == INTEGER_CST))
+       {
+         t1 = optimize_bit_field_compare (code, type, arg0, arg1);
+         if (t1)
+           return t1;
+       }
+
+      /* Optimize comparisons of strlen vs zero to a compare of the
+        first character of the string vs zero.  To wit,
+               strlen(ptr) == 0   =>  *ptr == 0
+               strlen(ptr) != 0   =>  *ptr != 0
+        Other cases should reduce to one of these two (or a constant)
+        due to the return value of strlen being unsigned.  */
+      if (TREE_CODE (arg0) == CALL_EXPR
+         && integer_zerop (arg1))
+       {
+         tree fndecl = get_callee_fndecl (arg0);
+         tree arglist;
+
+         if (fndecl
+             && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+             && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
+             && (arglist = TREE_OPERAND (arg0, 1))
+             && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
+             && ! TREE_CHAIN (arglist))
+           {
+             tree iref = build_fold_indirect_ref (TREE_VALUE (arglist));
+             return fold_build2 (code, type, iref,
+                                 build_int_cst (TREE_TYPE (iref), 0));
+           }
+       }
+
+      /* Fold (X >> C) != 0 into X < 0 if C is one less than the width
+        of X.  Similarly fold (X >> C) == 0 into X >= 0.  */
+      if (TREE_CODE (arg0) == RSHIFT_EXPR
+         && integer_zerop (arg1)
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       {
+         tree arg00 = TREE_OPERAND (arg0, 0);
+         tree arg01 = TREE_OPERAND (arg0, 1);
+         tree itype = TREE_TYPE (arg00);
+         if (TREE_INT_CST_HIGH (arg01) == 0
+             && TREE_INT_CST_LOW (arg01)
+                == (unsigned HOST_WIDE_INT) (TYPE_PRECISION (itype) - 1))
+           {
+             if (TYPE_UNSIGNED (itype))
+               {
+                 itype = lang_hooks.types.signed_type (itype);
+                 arg00 = fold_convert (itype, arg00);
+               }
+             return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
+                                 type, arg00, build_int_cst (itype, 0));
+           }
+       }
+
+      /* (X ^ Y) == 0 becomes X == Y, and (X ^ Y) != 0 becomes X != Y.  */
+      if (integer_zerop (arg1)
+         && TREE_CODE (arg0) == BIT_XOR_EXPR)
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                           TREE_OPERAND (arg0, 1));
+
+      /* (X ^ Y) == Y becomes X == 0.  We know that Y has no side-effects.  */
+      if (TREE_CODE (arg0) == BIT_XOR_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                           build_int_cst (TREE_TYPE (arg1), 0));
+      /* Likewise (X ^ Y) == X becomes Y == 0.  X has no side-effects.  */
+      if (TREE_CODE (arg0) == BIT_XOR_EXPR
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 1),
+                           build_int_cst (TREE_TYPE (arg1), 0));
+
+      /* (X ^ C1) op C2 can be rewritten as X op (C1 ^ C2).  */
+      if (TREE_CODE (arg0) == BIT_XOR_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                           fold_build2 (BIT_XOR_EXPR, TREE_TYPE (arg1),
+                                        TREE_OPERAND (arg0, 1), arg1));
+
+      /* Fold (~X & C) == 0 into (X & C) != 0 and (~X & C) != 0 into
+        (X & C) == 0 when C is a single bit.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_NOT_EXPR
+         && integer_zerop (arg1)
+         && integer_pow2p (TREE_OPERAND (arg0, 1)))
+       {
+         tem = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                            TREE_OPERAND (TREE_OPERAND (arg0, 0), 0),
+                            TREE_OPERAND (arg0, 1));
+         return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR,
+                             type, tem, arg1);
+       }
+
+      /* Fold ((X & C) ^ C) eq/ne 0 into (X & C) ne/eq 0, when the
+        constant C is a power of two, i.e. a single bit.  */
+      if (TREE_CODE (arg0) == BIT_XOR_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR
+         && integer_zerop (arg1)
+         && integer_pow2p (TREE_OPERAND (arg0, 1))
+         && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1),
+                             TREE_OPERAND (arg0, 1), OEP_ONLY_CONST))
+       {
+         tree arg00 = TREE_OPERAND (arg0, 0);
+         return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
+                             arg00, build_int_cst (TREE_TYPE (arg00), 0));
+       }
+
+      /* Likewise, fold ((X ^ C) & C) eq/ne 0 into (X & C) ne/eq 0,
+        when is C is a power of two, i.e. a single bit.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_XOR_EXPR
+         && integer_zerop (arg1)
+         && integer_pow2p (TREE_OPERAND (arg0, 1))
+         && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1),
+                             TREE_OPERAND (arg0, 1), OEP_ONLY_CONST))
+       {
+         tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+         tem = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg000),
+                            arg000, TREE_OPERAND (arg0, 1));
+         return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
+                             tem, build_int_cst (TREE_TYPE (tem), 0));
+       }
+
+      /* If this is a comparison of two exprs that look like an
+        ARRAY_REF of the same object, then we can fold this to a
+        comparison of the two offsets.  This is only safe for
+        EQ_EXPR and NE_EXPR because of overflow issues.  */
+      {
+       tree base0, offset0, base1, offset1;
+
+       if (extract_array_ref (arg0, &base0, &offset0)
+           && extract_array_ref (arg1, &base1, &offset1)
+           && operand_equal_p (base0, base1, 0))
+          {
+           /* Handle no offsets on both sides specially.  */
+           if (offset0 == NULL_TREE && offset1 == NULL_TREE)
+             return fold_build2 (code, type, integer_zero_node,
+                                 integer_zero_node);
+
+           if (!offset0 || !offset1
+               || TREE_TYPE (offset0) == TREE_TYPE (offset1))
+             {
+               if (offset0 == NULL_TREE)
+                 offset0 = build_int_cst (TREE_TYPE (offset1), 0);
+               if (offset1 == NULL_TREE)
+                 offset1 = build_int_cst (TREE_TYPE (offset0), 0);
+               return fold_build2 (code, type, offset0, offset1);
+             }
+         }
+      }
+
+      if (integer_zerop (arg1)
+         && tree_expr_nonzero_p (arg0))
+        {
+         tree res = constant_boolean_node (code==NE_EXPR, type);
+         return omit_one_operand (type, res, arg0);
+       }
+      return NULL_TREE;
+
+    case LT_EXPR:
+    case GT_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+      tem = fold_comparison (code, type, op0, op1);
+      if (tem != NULL_TREE)
+       return tem;
+
+      /* Transform comparisons of the form X +- C CMP X.  */
+      if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+              && !HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
+             || (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+                 && !TYPE_UNSIGNED (TREE_TYPE (arg1))
+                 && !(flag_wrapv || flag_trapv))))
+       {
+         tree arg01 = TREE_OPERAND (arg0, 1);
+         enum tree_code code0 = TREE_CODE (arg0);
+         int is_positive;
+
+         if (TREE_CODE (arg01) == REAL_CST)
+           is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1;
+         else
+           is_positive = tree_int_cst_sgn (arg01);
+
+         /* (X - c) > X becomes false.  */
+         if (code == GT_EXPR
+             && ((code0 == MINUS_EXPR && is_positive >= 0)
+                 || (code0 == PLUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (0, type);
 
-      /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
-        and similarly for >= into !=.  */
-      if ((code == LT_EXPR || code == GE_EXPR)
-         && TYPE_UNSIGNED (TREE_TYPE (arg0))
-         && TREE_CODE (arg1) == LSHIFT_EXPR
-         && integer_onep (TREE_OPERAND (arg1, 0)))
-       return build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
-                      build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
-                              TREE_OPERAND (arg1, 1)),
-                      fold_convert (TREE_TYPE (arg0), integer_zero_node));
-
-      else if ((code == LT_EXPR || code == GE_EXPR)
-              && TYPE_UNSIGNED (TREE_TYPE (arg0))
-              && (TREE_CODE (arg1) == NOP_EXPR
-                  || TREE_CODE (arg1) == CONVERT_EXPR)
-              && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
-              && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
-       return
-         build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
-                 fold_convert (TREE_TYPE (arg0),
-                               build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
-                                       TREE_OPERAND (TREE_OPERAND (arg1, 0),
-                                                     1))),
-                 fold_convert (TREE_TYPE (arg0), integer_zero_node));
+         /* Likewise (X + c) < X becomes false.  */
+         if (code == LT_EXPR
+             && ((code0 == PLUS_EXPR && is_positive >= 0)
+                 || (code0 == MINUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (0, type);
 
-      /* Simplify comparison of something with itself.  (For IEEE
-        floating-point, we can only do some of these simplifications.)  */
-      if (operand_equal_p (arg0, arg1, 0))
-       {
-         switch (code)
+         /* Convert (X - c) <= X to true.  */
+         if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
+             && code == LE_EXPR
+             && ((code0 == MINUS_EXPR && is_positive >= 0)
+                 || (code0 == PLUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (1, type);
+
+         /* Convert (X + c) >= X to true.  */
+         if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
+             && code == GE_EXPR
+             && ((code0 == PLUS_EXPR && is_positive >= 0)
+                 || (code0 == MINUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (1, type);
+
+         if (TREE_CODE (arg01) == INTEGER_CST)
            {
-           case EQ_EXPR:
-             if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
-                 || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+             /* Convert X + c > X and X - c < X to true for integers.  */
+             if (code == GT_EXPR
+                 && ((code0 == PLUS_EXPR && is_positive > 0)
+                     || (code0 == MINUS_EXPR && is_positive < 0)))
                return constant_boolean_node (1, type);
-             break;
 
-           case GE_EXPR:
-           case LE_EXPR:
-             if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
-                 || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+             if (code == LT_EXPR
+                 && ((code0 == MINUS_EXPR && is_positive > 0)
+                     || (code0 == PLUS_EXPR && is_positive < 0)))
                return constant_boolean_node (1, type);
-             return fold_build2 (EQ_EXPR, type, arg0, arg1);
 
-           case NE_EXPR:
-             /* For NE, we can only do this simplification if integer
-                or we don't honor IEEE floating point NaNs.  */
-             if (FLOAT_TYPE_P (TREE_TYPE (arg0))
-                 && HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
-               break;
-             /* ... fall through ...  */
-           case GT_EXPR:
-           case LT_EXPR:
-             return constant_boolean_node (0, type);
-           default:
-             gcc_unreachable ();
+             /* Convert X + c <= X and X - c >= X to false for integers.  */
+             if (code == LE_EXPR
+                 && ((code0 == PLUS_EXPR && is_positive > 0)
+                     || (code0 == MINUS_EXPR && is_positive < 0)))
+               return constant_boolean_node (0, type);
+
+             if (code == GE_EXPR
+                 && ((code0 == MINUS_EXPR && is_positive > 0)
+                     || (code0 == PLUS_EXPR && is_positive < 0)))
+               return constant_boolean_node (0, type);
            }
        }
 
-      /* If we are comparing an expression that just has comparisons
-        of two integer values, arithmetic expressions of those comparisons,
-        and constants, we can simplify it.  There are only three cases
-        to check: the two values can either be equal, the first can be
-        greater, or the second can be greater.  Fold the expression for
-        those three values.  Since each value must be 0 or 1, we have
-        eight possibilities, each of which corresponds to the constant 0
-        or 1 or one of the six possible comparisons.
-
-        This handles common cases like (a > b) == 0 but also handles
-        expressions like  ((x > y) - (y > x)) > 0, which supposedly
-        occur in macroized code.  */
-
-      if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST)
-       {
-         tree cval1 = 0, cval2 = 0;
-         int save_p = 0;
-
-         if (twoval_comparison_p (arg0, &cval1, &cval2, &save_p)
-             /* Don't handle degenerate cases here; they should already
-                have been handled anyway.  */
-             && cval1 != 0 && cval2 != 0
-             && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
-             && TREE_TYPE (cval1) == TREE_TYPE (cval2)
-             && INTEGRAL_TYPE_P (TREE_TYPE (cval1))
-             && TYPE_MAX_VALUE (TREE_TYPE (cval1))
-             && TYPE_MAX_VALUE (TREE_TYPE (cval2))
-             && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
-                                   TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
+      /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
+        This transformation affects the cases which are handled in later
+        optimizations involving comparisons with non-negative constants.  */
+      if (TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (arg0) != INTEGER_CST
+         && tree_int_cst_sgn (arg1) > 0)
+       {
+         if (code == GE_EXPR)
+           {
+             arg1 = const_binop (MINUS_EXPR, arg1,
+                                 build_int_cst (TREE_TYPE (arg1), 1), 0);
+             return fold_build2 (GT_EXPR, type, arg0,
+                                 fold_convert (TREE_TYPE (arg0), arg1));
+           }
+         if (code == LT_EXPR)
            {
-             tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1));
-             tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1));
+             arg1 = const_binop (MINUS_EXPR, arg1,
+                                 build_int_cst (TREE_TYPE (arg1), 1), 0);
+             return fold_build2 (LE_EXPR, type, arg0,
+                                 fold_convert (TREE_TYPE (arg0), arg1));
+           }
+       }
 
-             /* We can't just pass T to eval_subst in case cval1 or cval2
-                was the same as ARG1.  */
+      /* Comparisons with the highest or lowest possible integer of
+        the specified size will have known values.  */
+      {
+       int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg1)));
 
-             tree high_result
-               = fold_build2 (code, type,
-                              eval_subst (arg0, cval1, maxval,
-                                          cval2, minval),
-                              arg1);
-             tree equal_result
-               = fold_build2 (code, type,
-                              eval_subst (arg0, cval1, maxval,
-                                          cval2, maxval),
-                              arg1);
-             tree low_result
-               = fold_build2 (code, type,
-                              eval_subst (arg0, cval1, minval,
-                                          cval2, maxval),
-                              arg1);
+       if (TREE_CODE (arg1) == INTEGER_CST
+           && ! TREE_CONSTANT_OVERFLOW (arg1)
+           && width <= 2 * HOST_BITS_PER_WIDE_INT
+           && (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+               || POINTER_TYPE_P (TREE_TYPE (arg1))))
+         {
+           HOST_WIDE_INT signed_max_hi;
+           unsigned HOST_WIDE_INT signed_max_lo;
+           unsigned HOST_WIDE_INT max_hi, max_lo, min_hi, min_lo;
+
+           if (width <= HOST_BITS_PER_WIDE_INT)
+             {
+               signed_max_lo = ((unsigned HOST_WIDE_INT) 1 << (width - 1))
+                               - 1;
+               signed_max_hi = 0;
+               max_hi = 0;
+
+               if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
+                 {
+                   max_lo = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
+                   min_lo = 0;
+                   min_hi = 0;
+                 }
+               else
+                 {
+                   max_lo = signed_max_lo;
+                   min_lo = ((unsigned HOST_WIDE_INT) -1 << (width - 1));
+                   min_hi = -1;
+                 }
+             }
+           else
+             {
+               width -= HOST_BITS_PER_WIDE_INT;
+               signed_max_lo = -1;
+               signed_max_hi = ((unsigned HOST_WIDE_INT) 1 << (width - 1))
+                               - 1;
+               max_lo = -1;
+               min_lo = 0;
 
-             /* All three of these results should be 0 or 1.  Confirm they
-                are.  Then use those values to select the proper code
-                to use.  */
+               if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
+                 {
+                   max_hi = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
+                   min_hi = 0;
+                 }
+               else
+                 {
+                   max_hi = signed_max_hi;
+                   min_hi = ((unsigned HOST_WIDE_INT) -1 << (width - 1));
+                 }
+             }
 
-             if ((integer_zerop (high_result)
-                  || integer_onep (high_result))
-                 && (integer_zerop (equal_result)
-                     || integer_onep (equal_result))
-                 && (integer_zerop (low_result)
-                     || integer_onep (low_result)))
+           if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1) == max_hi
+               && TREE_INT_CST_LOW (arg1) == max_lo)
+             switch (code)
                {
-                 /* Make a 3-bit mask with the high-order bit being the
-                    value for `>', the next for '=', and the low for '<'.  */
-                 switch ((integer_onep (high_result) * 4)
-                         + (integer_onep (equal_result) * 2)
-                         + integer_onep (low_result))
-                   {
-                   case 0:
-                     /* Always false.  */
-                     return omit_one_operand (type, integer_zero_node, arg0);
-                   case 1:
-                     code = LT_EXPR;
-                     break;
-                   case 2:
-                     code = EQ_EXPR;
-                     break;
-                   case 3:
-                     code = LE_EXPR;
-                     break;
-                   case 4:
-                     code = GT_EXPR;
-                     break;
-                   case 5:
-                     code = NE_EXPR;
-                     break;
-                   case 6:
-                     code = GE_EXPR;
-                     break;
-                   case 7:
-                     /* Always true.  */
-                     return omit_one_operand (type, integer_one_node, arg0);
-                   }
+               case GT_EXPR:
+                 return omit_one_operand (type, integer_zero_node, arg0);
 
-                 if (save_p)
-                   return save_expr (build2 (code, type, cval1, cval2));
-                 else
-                   return fold_build2 (code, type, cval1, cval2);
+               case GE_EXPR:
+                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+
+               case LE_EXPR:
+                 return omit_one_operand (type, integer_one_node, arg0);
+
+               case LT_EXPR:
+                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+
+               /* The GE_EXPR and LT_EXPR cases above are not normally
+                  reached because of previous transformations.  */
+
+               default:
+                 break;
                }
-           }
-       }
+           else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
+                    == max_hi
+                    && TREE_INT_CST_LOW (arg1) == max_lo - 1)
+             switch (code)
+               {
+               case GT_EXPR:
+                 arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
+                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+               case LE_EXPR:
+                 arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
+                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+               default:
+                 break;
+               }
+           else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
+                    == min_hi
+                    && TREE_INT_CST_LOW (arg1) == min_lo)
+             switch (code)
+               {
+               case LT_EXPR:
+                 return omit_one_operand (type, integer_zero_node, arg0);
 
-      /* If this is a comparison of a field, we may be able to simplify it.  */
-      if (((TREE_CODE (arg0) == COMPONENT_REF
-           && lang_hooks.can_use_bit_fields_p ())
-          || TREE_CODE (arg0) == BIT_FIELD_REF)
-         && (code == EQ_EXPR || code == NE_EXPR)
-         /* Handle the constant case even without -O
-            to make sure the warnings are given.  */
-         && (optimize || TREE_CODE (arg1) == INTEGER_CST))
-       {
-         t1 = optimize_bit_field_compare (code, type, arg0, arg1);
-         if (t1)
-           return t1;
-       }
+               case LE_EXPR:
+                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+
+               case GE_EXPR:
+                 return omit_one_operand (type, integer_one_node, arg0);
+
+               case GT_EXPR:
+                 return fold_build2 (NE_EXPR, type, op0, op1);
+
+               default:
+                 break;
+               }
+           else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
+                    == min_hi
+                    && TREE_INT_CST_LOW (arg1) == min_lo + 1)
+             switch (code)
+               {
+               case GE_EXPR:
+                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+               case LT_EXPR:
+                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+               default:
+                 break;
+               }
+
+           else if (!in_gimple_form
+                    && TREE_INT_CST_HIGH (arg1) == signed_max_hi
+                    && TREE_INT_CST_LOW (arg1) == signed_max_lo
+                    && TYPE_UNSIGNED (TREE_TYPE (arg1))
+                    /* signed_type does not work on pointer types.  */
+                    && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
+             {
+               /* The following case also applies to X < signed_max+1
+                  and X >= signed_max+1 because previous transformations.  */
+               if (code == LE_EXPR || code == GT_EXPR)
+                 {
+                   tree st0, st1;
+                   st0 = lang_hooks.types.signed_type (TREE_TYPE (arg0));
+                   st1 = lang_hooks.types.signed_type (TREE_TYPE (arg1));
+                   return fold_build2 (code == LE_EXPR ? GE_EXPR: LT_EXPR,
+                                       type, fold_convert (st0, arg0),
+                                       build_int_cst (st1, 0));
+                 }
+             }
+         }
+      }
 
-      /* Fold a comparison of the address of COMPONENT_REFs with the same
-         type and component to a comparison of the address of the base
-        object.  In short, &x->a OP &y->a to x OP y and
-         &x->a OP &y.a to x OP &y  */
-      if (TREE_CODE (arg0) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF
-         && TREE_CODE (arg1) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF)
-        {
-         tree cref0 = TREE_OPERAND (arg0, 0);
-         tree cref1 = TREE_OPERAND (arg1, 0);
-         if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1))
-           {
-             tree op0 = TREE_OPERAND (cref0, 0);
-             tree op1 = TREE_OPERAND (cref1, 0);
-             return fold_build2 (code, type,
-                                 build_fold_addr_expr (op0),
-                                 build_fold_addr_expr (op1));
-           }
-       }
+      /* If we are comparing an ABS_EXPR with a constant, we can
+        convert all the cases into explicit comparisons, but they may
+        well not be faster than doing the ABS and one comparison.
+        But ABS (X) <= C is a range comparison, which becomes a subtraction
+        and a comparison, and is probably faster.  */
+      if (code == LE_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (arg0) == ABS_EXPR
+         && ! TREE_SIDE_EFFECTS (arg0)
+         && (0 != (tem = negate_expr (arg1)))
+         && TREE_CODE (tem) == INTEGER_CST
+         && ! TREE_CONSTANT_OVERFLOW (tem))
+       return fold_build2 (TRUTH_ANDIF_EXPR, type,
+                           build2 (GE_EXPR, type,
+                                   TREE_OPERAND (arg0, 0), tem),
+                           build2 (LE_EXPR, type,
+                                   TREE_OPERAND (arg0, 0), arg1));
 
-      /* Optimize comparisons of strlen vs zero to a compare of the
-        first character of the string vs zero.  To wit,
-               strlen(ptr) == 0   =>  *ptr == 0
-               strlen(ptr) != 0   =>  *ptr != 0
-        Other cases should reduce to one of these two (or a constant)
-        due to the return value of strlen being unsigned.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && integer_zerop (arg1)
-         && TREE_CODE (arg0) == CALL_EXPR)
-       {
-         tree fndecl = get_callee_fndecl (arg0);
-         tree arglist;
+      /* Convert ABS_EXPR<x> >= 0 to true.  */
+      if (code == GE_EXPR
+         && tree_expr_nonnegative_p (arg0)
+         && (integer_zerop (arg1)
+             || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
+                 && real_zerop (arg1))))
+       return omit_one_operand (type, integer_one_node, arg0);
 
-         if (fndecl
-             && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-             && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
-             && (arglist = TREE_OPERAND (arg0, 1))
-             && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
-             && ! TREE_CHAIN (arglist))
-           {
-             tree iref = build_fold_indirect_ref (TREE_VALUE (arglist));
-             return fold_build2 (code, type, iref,
-                                 build_int_cst (TREE_TYPE (iref), 0));
-           }
-       }
+      /* Convert ABS_EXPR<x> < 0 to false.  */
+      if (code == LT_EXPR
+         && tree_expr_nonnegative_p (arg0)
+         && (integer_zerop (arg1) || real_zerop (arg1)))
+       return omit_one_operand (type, integer_zero_node, arg0);
 
-      /* We can fold X/C1 op C2 where C1 and C2 are integer constants
-        into a single range test.  */
-      if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
-          || TREE_CODE (arg0) == EXACT_DIV_EXPR)
-         && TREE_CODE (arg1) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-         && !integer_zerop (TREE_OPERAND (arg0, 1))
-         && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
-         && !TREE_OVERFLOW (arg1))
-       {
-         t1 = fold_div_compare (code, type, arg0, arg1);
-         if (t1 != NULL_TREE)
-           return t1;
-       }
+      /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
+        and similarly for >= into !=.  */
+      if ((code == LT_EXPR || code == GE_EXPR)
+         && TYPE_UNSIGNED (TREE_TYPE (arg0))
+         && TREE_CODE (arg1) == LSHIFT_EXPR
+         && integer_onep (TREE_OPERAND (arg1, 0)))
+       return build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+                      build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+                              TREE_OPERAND (arg1, 1)),
+                      build_int_cst (TREE_TYPE (arg0), 0));
 
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && !TREE_SIDE_EFFECTS (arg0)
-         && integer_zerop (arg1)
-         && tree_expr_nonzero_p (arg0))
-       return constant_boolean_node (code==NE_EXPR, type);
+      if ((code == LT_EXPR || code == GE_EXPR)
+         && TYPE_UNSIGNED (TREE_TYPE (arg0))
+         && (TREE_CODE (arg1) == NOP_EXPR
+             || TREE_CODE (arg1) == CONVERT_EXPR)
+         && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
+         && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
+       return
+         build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+                 fold_convert (TREE_TYPE (arg0),
+                               build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+                                       TREE_OPERAND (TREE_OPERAND (arg1, 0),
+                                                     1))),
+                 build_int_cst (TREE_TYPE (arg0), 0));
 
-      t1 = fold_relational_const (code, type, arg0, arg1);
-      return t1 == NULL_TREE ? NULL_TREE : t1;
+      return NULL_TREE;
 
     case UNORDERED_EXPR:
     case ORDERED_EXPR:
@@ -9775,7 +10863,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       return pedantic_non_lvalue (tem);
 
     case COMPLEX_EXPR:
-      if (wins)
+      if ((TREE_CODE (arg0) == REAL_CST
+          && TREE_CODE (arg1) == REAL_CST)
+         || (TREE_CODE (arg0) == INTEGER_CST
+             && TREE_CODE (arg1) == INTEGER_CST))
        return build_complex (type, arg0, arg1);
       return NULL_TREE;
 
@@ -9861,9 +10952,11 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
       if (TREE_CODE (arg0) == CONSTRUCTOR
          && ! type_contains_placeholder_p (TREE_TYPE (arg0)))
        {
-         tree m = purpose_member (arg1, CONSTRUCTOR_ELTS (arg0));
-         if (m)
-           return TREE_VALUE (m);
+         unsigned HOST_WIDE_INT idx;
+         tree field, value;
+         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, field, value)
+           if (field == arg1)
+             return value;
        }
       return NULL_TREE;
 
@@ -9921,7 +11014,8 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
 
       /* If the second operand is simpler than the third, swap them
         since that produces better jump optimization results.  */
-      if (tree_swap_operands_p (op1, op2, false))
+      if (truth_value_p (TREE_CODE (arg0))
+         && tree_swap_operands_p (op1, op2, false))
        {
          /* See if this can be inverted.  If it can't, possibly because
             it was a floating-point inequality comparison, don't do
@@ -9993,7 +11087,9 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
       if (integer_zerop (op2)
          && truth_value_p (TREE_CODE (arg0))
          && truth_value_p (TREE_CODE (arg1)))
-       return fold_build2 (TRUTH_ANDIF_EXPR, type, arg0, arg1);
+       return fold_build2 (TRUTH_ANDIF_EXPR, type,
+                           fold_convert (type, arg0),
+                           arg1);
 
       /* Convert A ? B : 1 into !A || B if A and B are truth values.  */
       if (integer_onep (op2)
@@ -10003,7 +11099,9 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
          /* Only perform transformation if ARG0 is easily inverted.  */
          tem = invert_truthvalue (arg0);
          if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
-           return fold_build2 (TRUTH_ORIF_EXPR, type, tem, arg1);
+           return fold_build2 (TRUTH_ORIF_EXPR, type,
+                               fold_convert (type, tem),
+                               arg1);
        }
 
       /* Convert A ? 0 : B into !A && B if A and B are truth values.  */
@@ -10014,14 +11112,18 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
          /* Only perform transformation if ARG0 is easily inverted.  */
          tem = invert_truthvalue (arg0);
          if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
-           return fold_build2 (TRUTH_ANDIF_EXPR, type, tem, op2);
+           return fold_build2 (TRUTH_ANDIF_EXPR, type,
+                               fold_convert (type, tem),
+                               op2);
        }
 
       /* Convert A ? 1 : B into A || B if A and B are truth values.  */
       if (integer_onep (arg1)
          && truth_value_p (TREE_CODE (arg0))
          && truth_value_p (TREE_CODE (op2)))
-       return fold_build2 (TRUTH_ORIF_EXPR, type, arg0, op2);
+       return fold_build2 (TRUTH_ORIF_EXPR, type,
+                           fold_convert (type, arg0),
+                           op2);
 
       return NULL_TREE;
 
@@ -10030,13 +11132,7 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
       if (TREE_CODE (op0) == ADDR_EXPR
          && TREE_CODE (TREE_OPERAND (op0, 0)) == FUNCTION_DECL
          && DECL_BUILT_IN (TREE_OPERAND (op0, 0)))
-       {
-         tree fndecl = TREE_OPERAND (op0, 0);
-         tree arglist = op1;
-         tree tmp = fold_builtin (fndecl, arglist, false);
-         if (tmp)
-           return tmp;
-       }
+       return fold_builtin (TREE_OPERAND (op0, 0), op1, false);
       return NULL_TREE;
 
     case BIT_FIELD_REF:
@@ -10198,14 +11294,14 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
 {
   void **slot;
   enum tree_code code;
-  char buf[sizeof (struct tree_decl_non_common)];
+  struct tree_function_decl buf;
   int i, len;
   
 recursive_label:
 
   gcc_assert ((sizeof (struct tree_exp) + 5 * sizeof (tree)
-              <= sizeof (struct tree_decl_non_common))
-             && sizeof (struct tree_type) <= sizeof (struct tree_decl_non_common));
+              <= sizeof (struct tree_function_decl))
+             && sizeof (struct tree_type) <= sizeof (struct tree_function_decl));
   if (expr == NULL)
     return;
   slot = htab_find_slot (ht, expr, INSERT);
@@ -10217,8 +11313,8 @@ recursive_label:
       && DECL_ASSEMBLER_NAME_SET_P (expr))
     {
       /* Allow DECL_ASSEMBLER_NAME to be modified.  */
-      memcpy (buf, expr, tree_size (expr));
-      expr = (tree) buf;
+      memcpy ((char *) &buf, expr, tree_size (expr));
+      expr = (tree) &buf;
       SET_DECL_ASSEMBLER_NAME (expr, NULL);
     }
   else if (TREE_CODE_CLASS (code) == tcc_type
@@ -10227,8 +11323,8 @@ recursive_label:
               || TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)))
     {
       /* Allow these fields to be modified.  */
-      memcpy (buf, expr, tree_size (expr));
-      expr = (tree) buf;
+      memcpy ((char *) &buf, expr, tree_size (expr));
+      expr = (tree) &buf;
       TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) = 0;
       TYPE_POINTER_TO (expr) = NULL;
       TYPE_REFERENCE_TO (expr) = NULL;
@@ -10292,17 +11388,25 @@ recursive_label:
        fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht);
       break;
     case tcc_declaration:
-      fold_checksum_tree (DECL_SIZE (expr), ctx, ht);
-      fold_checksum_tree (DECL_SIZE_UNIT (expr), ctx, ht);
       fold_checksum_tree (DECL_NAME (expr), ctx, ht);
       fold_checksum_tree (DECL_CONTEXT (expr), ctx, ht);
-      fold_checksum_tree (DECL_ARGUMENTS (expr), ctx, ht);
-      fold_checksum_tree (DECL_RESULT_FLD (expr), ctx, ht);
-      fold_checksum_tree (DECL_INITIAL (expr), ctx, ht);
-      fold_checksum_tree (DECL_ABSTRACT_ORIGIN (expr), ctx, ht);
-      fold_checksum_tree (DECL_SECTION_NAME (expr), ctx, ht);
-      fold_checksum_tree (DECL_ATTRIBUTES (expr), ctx, ht);
-      fold_checksum_tree (DECL_VINDEX (expr), ctx, ht);
+      if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_COMMON))
+       {
+         fold_checksum_tree (DECL_SIZE (expr), ctx, ht);
+         fold_checksum_tree (DECL_SIZE_UNIT (expr), ctx, ht);
+         fold_checksum_tree (DECL_INITIAL (expr), ctx, ht);
+         fold_checksum_tree (DECL_ABSTRACT_ORIGIN (expr), ctx, ht);
+         fold_checksum_tree (DECL_ATTRIBUTES (expr), ctx, ht);
+       }
+      if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_WITH_VIS))
+       fold_checksum_tree (DECL_SECTION_NAME (expr), ctx, ht);
+         
+      if (CODE_CONTAINS_STRUCT (TREE_CODE (expr), TS_DECL_NON_COMMON))
+       {
+         fold_checksum_tree (DECL_VINDEX (expr), ctx, ht);
+         fold_checksum_tree (DECL_RESULT_FLD (expr), ctx, ht);
+         fold_checksum_tree (DECL_ARGUMENT_FLD (expr), ctx, ht);
+       }
       break;
     case tcc_type:
       if (TREE_CODE (expr) == ENUMERAL_TYPE)
@@ -10337,13 +11441,35 @@ recursive_label:
    operand OP0.  */
 
 tree
-fold_build1 (enum tree_code code, tree type, tree op0)
+fold_build1_stat (enum tree_code code, tree type, tree op0 MEM_STAT_DECL)
 {
-  tree tem = fold_unary (code, type, op0);
-  if (tem)
-    return tem;
+  tree tem;
+#ifdef ENABLE_FOLD_CHECKING
+  unsigned char checksum_before[16], checksum_after[16];
+  struct md5_ctx ctx;
+  htab_t ht;
+
+  ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op0, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before);
+  htab_empty (ht);
+#endif
+  
+  tem = fold_unary (code, type, op0);
+  if (!tem)
+    tem = build1_stat (code, type, op0 PASS_MEM_STAT);
+  
+#ifdef ENABLE_FOLD_CHECKING
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op0, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after);
+  htab_delete (ht);
 
-  return build1 (code, type, op0);
+  if (memcmp (checksum_before, checksum_after, 16))
+    fold_check_failed (op0, tem);
+#endif
+  return tem;
 }
 
 /* Fold a binary tree expression with code CODE of type TYPE with
@@ -10352,13 +11478,52 @@ fold_build1 (enum tree_code code, tree type, tree op0)
    with operands OP0 and OP1.  */
 
 tree
-fold_build2 (enum tree_code code, tree type, tree op0, tree op1)
+fold_build2_stat (enum tree_code code, tree type, tree op0, tree op1
+                 MEM_STAT_DECL)
 {
-  tree tem = fold_binary (code, type, op0, op1);
-  if (tem)
-    return tem;
+  tree tem;
+#ifdef ENABLE_FOLD_CHECKING
+  unsigned char checksum_before_op0[16],
+                checksum_before_op1[16],
+               checksum_after_op0[16],
+               checksum_after_op1[16];
+  struct md5_ctx ctx;
+  htab_t ht;
+
+  ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op0, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before_op0);
+  htab_empty (ht);
+
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op1, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before_op1);
+  htab_empty (ht);
+#endif
+
+  tem = fold_binary (code, type, op0, op1);
+  if (!tem)
+    tem = build2_stat (code, type, op0, op1 PASS_MEM_STAT);
+  
+#ifdef ENABLE_FOLD_CHECKING
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op0, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after_op0);
+  htab_empty (ht);
+
+  if (memcmp (checksum_before_op0, checksum_after_op0, 16))
+    fold_check_failed (op0, tem);
+  
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op1, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after_op1);
+  htab_delete (ht);
 
-  return build2 (code, type, op0, op1);
+  if (memcmp (checksum_before_op1, checksum_after_op1, 16))
+    fold_check_failed (op1, tem);
+#endif
+  return tem;
 }
 
 /* Fold a ternary tree expression with code CODE of type TYPE with
@@ -10367,43 +11532,129 @@ fold_build2 (enum tree_code code, tree type, tree op0, tree op1)
    type TYPE with operands OP0, OP1, and OP2.  */
 
 tree
-fold_build3 (enum tree_code code, tree type, tree op0, tree op1, tree op2)
+fold_build3_stat (enum tree_code code, tree type, tree op0, tree op1, tree op2
+            MEM_STAT_DECL)
 {
-  tree tem = fold_ternary (code, type, op0, op1, op2);
-  if (tem)
-    return tem;
+  tree tem;
+#ifdef ENABLE_FOLD_CHECKING
+  unsigned char checksum_before_op0[16],
+                checksum_before_op1[16],
+                checksum_before_op2[16],
+               checksum_after_op0[16],
+               checksum_after_op1[16],
+               checksum_after_op2[16];
+  struct md5_ctx ctx;
+  htab_t ht;
+
+  ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op0, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before_op0);
+  htab_empty (ht);
+
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op1, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before_op1);
+  htab_empty (ht);
+
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op2, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before_op2);
+  htab_empty (ht);
+#endif
+  
+  tem = fold_ternary (code, type, op0, op1, op2);
+  if (!tem)
+    tem =  build3_stat (code, type, op0, op1, op2 PASS_MEM_STAT);
+      
+#ifdef ENABLE_FOLD_CHECKING
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op0, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after_op0);
+  htab_empty (ht);
+
+  if (memcmp (checksum_before_op0, checksum_after_op0, 16))
+    fold_check_failed (op0, tem);
+  
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op1, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after_op1);
+  htab_empty (ht);
 
-  return build3 (code, type, op0, op1, op2);
+  if (memcmp (checksum_before_op1, checksum_after_op1, 16))
+    fold_check_failed (op1, tem);
+  
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (op2, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after_op2);
+  htab_delete (ht);
+
+  if (memcmp (checksum_before_op2, checksum_after_op2, 16))
+    fold_check_failed (op2, tem);
+#endif
+  return tem;
 }
 
 /* Perform constant folding and related simplification of initializer
-   expression EXPR.  This behaves identically to "fold" but ignores
+   expression EXPR.  These behave identically to "fold_buildN" but ignore
    potential run-time traps and exceptions that fold must preserve.  */
 
+#define START_FOLD_INIT \
+  int saved_signaling_nans = flag_signaling_nans;\
+  int saved_trapping_math = flag_trapping_math;\
+  int saved_rounding_math = flag_rounding_math;\
+  int saved_trapv = flag_trapv;\
+  flag_signaling_nans = 0;\
+  flag_trapping_math = 0;\
+  flag_rounding_math = 0;\
+  flag_trapv = 0
+
+#define END_FOLD_INIT \
+  flag_signaling_nans = saved_signaling_nans;\
+  flag_trapping_math = saved_trapping_math;\
+  flag_rounding_math = saved_rounding_math;\
+  flag_trapv = saved_trapv
+
+tree
+fold_build1_initializer (enum tree_code code, tree type, tree op)
+{
+  tree result;
+  START_FOLD_INIT;
+
+  result = fold_build1 (code, type, op);
+
+  END_FOLD_INIT;
+  return result;
+}
+
 tree
-fold_initializer (tree expr)
+fold_build2_initializer (enum tree_code code, tree type, tree op0, tree op1)
 {
-  int saved_signaling_nans = flag_signaling_nans;
-  int saved_trapping_math = flag_trapping_math;
-  int saved_rounding_math = flag_rounding_math;
-  int saved_trapv = flag_trapv;
   tree result;
+  START_FOLD_INIT;
 
-  flag_signaling_nans = 0;
-  flag_trapping_math = 0;
-  flag_rounding_math = 0;
-  flag_trapv = 0;
+  result = fold_build2 (code, type, op0, op1);
+
+  END_FOLD_INIT;
+  return result;
+}
 
-  result = fold (expr);
+tree
+fold_build3_initializer (enum tree_code code, tree type, tree op0, tree op1,
+                        tree op2)
+{
+  tree result;
+  START_FOLD_INIT;
 
-  flag_signaling_nans = saved_signaling_nans;
-  flag_trapping_math = saved_trapping_math;
-  flag_rounding_math = saved_rounding_math;
-  flag_trapv = saved_trapv;
+  result = fold_build3 (code, type, op0, op1, op2);
 
+  END_FOLD_INIT;
   return result;
 }
 
+#undef START_FOLD_INIT
+#undef END_FOLD_INIT
+
 /* Determine if first argument is a multiple of second argument.  Return 0 if
    it is not, or we cannot easily determined it to be.
 
@@ -10522,10 +11773,22 @@ multiple_of_p (tree type, tree top, tree bottom)
 int
 tree_expr_nonnegative_p (tree t)
 {
+  if (TYPE_UNSIGNED (TREE_TYPE (t)))
+    return 1;
+
   switch (TREE_CODE (t))
     {
+    case SSA_NAME:
+      /* Query VRP to see if it has recorded any information about
+        the range of this object.  */
+      return ssa_name_nonnegative_p (t);
+
     case ABS_EXPR:
-      return 1;
+      /* We can't return 1 if flag_wrapv is set because
+        ABS_EXPR<INT_MIN> = INT_MIN.  */
+      if (!(flag_wrapv && INTEGRAL_TYPE_P (TREE_TYPE (t))))
+        return 1;
+      break;
 
     case INTEGER_CST:
       return tree_int_cst_sgn (t) >= 0;
@@ -10581,6 +11844,15 @@ tree_expr_nonnegative_p (tree t)
        }
       return 0;
 
+    case BIT_AND_EXPR:
+    case MAX_EXPR:
+      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
+            || tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case MIN_EXPR:
+    case RDIV_EXPR:
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
@@ -10592,19 +11864,21 @@ tree_expr_nonnegative_p (tree t)
     case CEIL_MOD_EXPR:
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
+    case SAVE_EXPR:
+    case NON_LVALUE_EXPR:
+    case FLOAT_EXPR:
       return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
 
-    case RDIV_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
-            && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+    case COMPOUND_EXPR:
+    case MODIFY_EXPR:
+      return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
 
-    case BIT_AND_EXPR:
+    case BIND_EXPR:
+      return tree_expr_nonnegative_p (expr_last (TREE_OPERAND (t, 1)));
+
+    case COND_EXPR:
       return tree_expr_nonnegative_p (TREE_OPERAND (t, 1))
-            || tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
-            && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+            && tree_expr_nonnegative_p (TREE_OPERAND (t, 2));
 
     case NOP_EXPR:
       {
@@ -10633,28 +11907,6 @@ tree_expr_nonnegative_p (tree t)
       }
       break;
 
-    case COND_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 1))
-       && tree_expr_nonnegative_p (TREE_OPERAND (t, 2));
-    case COMPOUND_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
-    case MIN_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
-       && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
-    case MAX_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
-       || tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
-    case MODIFY_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
-    case BIND_EXPR:
-      return tree_expr_nonnegative_p (expr_last (TREE_OPERAND (t, 1)));
-    case SAVE_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
-    case NON_LVALUE_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
-    case FLOAT_EXPR:
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
-
     case TARGET_EXPR:
       {
        tree temp = TARGET_EXPR_SLOT (t);
@@ -10693,84 +11945,77 @@ tree_expr_nonnegative_p (tree t)
        if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
          switch (DECL_FUNCTION_CODE (fndecl))
            {
-#define CASE_BUILTIN_F(BUILT_IN_FN) \
-  case BUILT_IN_FN: case BUILT_IN_FN##F: case BUILT_IN_FN##L:
-#define CASE_BUILTIN_I(BUILT_IN_FN) \
-  case BUILT_IN_FN: case BUILT_IN_FN##L: case BUILT_IN_FN##LL:
-
-           CASE_BUILTIN_F (BUILT_IN_ACOS)
-           CASE_BUILTIN_F (BUILT_IN_ACOSH)
-           CASE_BUILTIN_F (BUILT_IN_CABS)
-           CASE_BUILTIN_F (BUILT_IN_COSH)
-           CASE_BUILTIN_F (BUILT_IN_ERFC)
-           CASE_BUILTIN_F (BUILT_IN_EXP)
-           CASE_BUILTIN_F (BUILT_IN_EXP10)
-           CASE_BUILTIN_F (BUILT_IN_EXP2)
-           CASE_BUILTIN_F (BUILT_IN_FABS)
-           CASE_BUILTIN_F (BUILT_IN_FDIM)
-           CASE_BUILTIN_F (BUILT_IN_FREXP)
-           CASE_BUILTIN_F (BUILT_IN_HYPOT)
-           CASE_BUILTIN_F (BUILT_IN_POW10)
-           CASE_BUILTIN_I (BUILT_IN_FFS)
-           CASE_BUILTIN_I (BUILT_IN_PARITY)
-           CASE_BUILTIN_I (BUILT_IN_POPCOUNT)
+           CASE_FLT_FN (BUILT_IN_ACOS):
+           CASE_FLT_FN (BUILT_IN_ACOSH):
+           CASE_FLT_FN (BUILT_IN_CABS):
+           CASE_FLT_FN (BUILT_IN_COSH):
+           CASE_FLT_FN (BUILT_IN_ERFC):
+           CASE_FLT_FN (BUILT_IN_EXP):
+           CASE_FLT_FN (BUILT_IN_EXP10):
+           CASE_FLT_FN (BUILT_IN_EXP2):
+           CASE_FLT_FN (BUILT_IN_FABS):
+           CASE_FLT_FN (BUILT_IN_FDIM):
+           CASE_FLT_FN (BUILT_IN_HYPOT):
+           CASE_FLT_FN (BUILT_IN_POW10):
+           CASE_INT_FN (BUILT_IN_FFS):
+           CASE_INT_FN (BUILT_IN_PARITY):
+           CASE_INT_FN (BUILT_IN_POPCOUNT):
              /* Always true.  */
              return 1;
 
-           CASE_BUILTIN_F (BUILT_IN_SQRT)
+           CASE_FLT_FN (BUILT_IN_SQRT):
              /* sqrt(-0.0) is -0.0.  */
              if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
                return 1;
              return tree_expr_nonnegative_p (TREE_VALUE (arglist));
 
-           CASE_BUILTIN_F (BUILT_IN_ASINH)
-           CASE_BUILTIN_F (BUILT_IN_ATAN)
-           CASE_BUILTIN_F (BUILT_IN_ATANH)
-           CASE_BUILTIN_F (BUILT_IN_CBRT)
-           CASE_BUILTIN_F (BUILT_IN_CEIL)
-           CASE_BUILTIN_F (BUILT_IN_ERF)
-           CASE_BUILTIN_F (BUILT_IN_EXPM1)
-           CASE_BUILTIN_F (BUILT_IN_FLOOR)
-           CASE_BUILTIN_F (BUILT_IN_FMOD)
-           CASE_BUILTIN_F (BUILT_IN_LCEIL)
-           CASE_BUILTIN_F (BUILT_IN_LDEXP)
-           CASE_BUILTIN_F (BUILT_IN_LFLOOR)
-           CASE_BUILTIN_F (BUILT_IN_LLCEIL)
-           CASE_BUILTIN_F (BUILT_IN_LLFLOOR)
-           CASE_BUILTIN_F (BUILT_IN_LLRINT)
-           CASE_BUILTIN_F (BUILT_IN_LLROUND)
-           CASE_BUILTIN_F (BUILT_IN_LRINT)
-           CASE_BUILTIN_F (BUILT_IN_LROUND)
-           CASE_BUILTIN_F (BUILT_IN_MODF)
-           CASE_BUILTIN_F (BUILT_IN_NEARBYINT)
-           CASE_BUILTIN_F (BUILT_IN_POW)
-           CASE_BUILTIN_F (BUILT_IN_RINT)
-           CASE_BUILTIN_F (BUILT_IN_ROUND)
-           CASE_BUILTIN_F (BUILT_IN_SIGNBIT)
-           CASE_BUILTIN_F (BUILT_IN_SINH)
-           CASE_BUILTIN_F (BUILT_IN_TANH)
-           CASE_BUILTIN_F (BUILT_IN_TRUNC)
+           CASE_FLT_FN (BUILT_IN_ASINH):
+           CASE_FLT_FN (BUILT_IN_ATAN):
+           CASE_FLT_FN (BUILT_IN_ATANH):
+           CASE_FLT_FN (BUILT_IN_CBRT):
+           CASE_FLT_FN (BUILT_IN_CEIL):
+           CASE_FLT_FN (BUILT_IN_ERF):
+           CASE_FLT_FN (BUILT_IN_EXPM1):
+           CASE_FLT_FN (BUILT_IN_FLOOR):
+           CASE_FLT_FN (BUILT_IN_FMOD):
+           CASE_FLT_FN (BUILT_IN_FREXP):
+           CASE_FLT_FN (BUILT_IN_LCEIL):
+           CASE_FLT_FN (BUILT_IN_LDEXP):
+           CASE_FLT_FN (BUILT_IN_LFLOOR):
+           CASE_FLT_FN (BUILT_IN_LLCEIL):
+           CASE_FLT_FN (BUILT_IN_LLFLOOR):
+           CASE_FLT_FN (BUILT_IN_LLRINT):
+           CASE_FLT_FN (BUILT_IN_LLROUND):
+           CASE_FLT_FN (BUILT_IN_LRINT):
+           CASE_FLT_FN (BUILT_IN_LROUND):
+           CASE_FLT_FN (BUILT_IN_MODF):
+           CASE_FLT_FN (BUILT_IN_NEARBYINT):
+           CASE_FLT_FN (BUILT_IN_POW):
+           CASE_FLT_FN (BUILT_IN_RINT):
+           CASE_FLT_FN (BUILT_IN_ROUND):
+           CASE_FLT_FN (BUILT_IN_SIGNBIT):
+           CASE_FLT_FN (BUILT_IN_SINH):
+           CASE_FLT_FN (BUILT_IN_TANH):
+           CASE_FLT_FN (BUILT_IN_TRUNC):
              /* True if the 1st argument is nonnegative.  */
              return tree_expr_nonnegative_p (TREE_VALUE (arglist));
 
-           CASE_BUILTIN_F (BUILT_IN_FMAX)
+           CASE_FLT_FN (BUILT_IN_FMAX):
              /* True if the 1st OR 2nd arguments are nonnegative.  */
              return tree_expr_nonnegative_p (TREE_VALUE (arglist))
                || tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
 
-           CASE_BUILTIN_F (BUILT_IN_FMIN)
+           CASE_FLT_FN (BUILT_IN_FMIN):
              /* True if the 1st AND 2nd arguments are nonnegative.  */
              return tree_expr_nonnegative_p (TREE_VALUE (arglist))
                && tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
 
-           CASE_BUILTIN_F (BUILT_IN_COPYSIGN)
+           CASE_FLT_FN (BUILT_IN_COPYSIGN):
              /* True if the 2nd argument is nonnegative.  */
              return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
 
            default:
              break;
-#undef CASE_BUILTIN_F
-#undef CASE_BUILTIN_I
            }
       }
 
@@ -10790,7 +12035,7 @@ tree_expr_nonnegative_p (tree t)
    For floating point we further ensure that T is not denormal.
    Similar logic is present in nonzero_address in rtlanal.h.  */
 
-static bool
+bool
 tree_expr_nonzero_p (tree t)
 {
   tree type = TREE_TYPE (t);
@@ -10801,9 +12046,13 @@ tree_expr_nonzero_p (tree t)
 
   switch (TREE_CODE (t))
     {
+    case SSA_NAME:
+      /* Query VRP to see if it has recorded any information about
+        the range of this object.  */
+      return ssa_name_nonzero_p (t);
+
     case ABS_EXPR:
-      if (!TYPE_UNSIGNED (type) && !flag_wrapv)
-       return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+      return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
 
     case INTEGER_CST:
       /* We used to test for !integer_zerop here.  This does not work correctly
@@ -10838,7 +12087,7 @@ tree_expr_nonzero_p (tree t)
        tree inner_type = TREE_TYPE (TREE_OPERAND (t, 0));
        tree outer_type = TREE_TYPE (t);
 
-       return (TYPE_PRECISION (inner_type) >= TYPE_PRECISION (outer_type)
+       return (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type)
                && tree_expr_nonzero_p (TREE_OPERAND (t, 0)));
       }
       break;
@@ -10898,6 +12147,9 @@ tree_expr_nonzero_p (tree t)
       return tree_expr_nonzero_p (TREE_OPERAND (t, 1))
             || tree_expr_nonzero_p (TREE_OPERAND (t, 0));
 
+    case CALL_EXPR:
+      return alloca_call_p (t);
+
     default:
       break;
     }
@@ -11281,9 +12533,15 @@ fold_indirect_ref_1 (tree type, tree op0)
     {
       tree op = TREE_OPERAND (sub, 0);
       tree optype = TREE_TYPE (op);
-      /* *&p => p */
+      /* *&p => p;  make sure to handle *&"str"[cst] here.  */
       if (type == optype)
-       return op;
+       {
+         tree fop = fold_read_from_constant_string (op);
+         if (fop)
+           return fop;
+         else
+           return op;
+       }
       /* *(foo *)&fooarray => fooarray[0] */
       else if (TREE_CODE (optype) == ARRAY_TYPE
               && type == TREE_TYPE (optype))
@@ -11294,8 +12552,32 @@ fold_indirect_ref_1 (tree type, tree op0)
            min_val = TYPE_MIN_VALUE (type_domain);
          return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
        }
+      /* *(foo *)&complexfoo => __real__ complexfoo */
+      else if (TREE_CODE (optype) == COMPLEX_TYPE
+              && type == TREE_TYPE (optype))
+       return fold_build1 (REALPART_EXPR, type, op);
     }
 
+  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+  if (TREE_CODE (sub) == PLUS_EXPR
+      && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
+    {
+      tree op00 = TREE_OPERAND (sub, 0);
+      tree op01 = TREE_OPERAND (sub, 1);
+      tree op00type;
+
+      STRIP_NOPS (op00);
+      op00type = TREE_TYPE (op00);
+      if (TREE_CODE (op00) == ADDR_EXPR
+         && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE
+         && type == TREE_TYPE (TREE_TYPE (op00type)))
+       {
+         tree size = TYPE_SIZE_UNIT (type);
+         if (tree_int_cst_equal (size, op01))
+           return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (op00, 0));
+       }
+    }
+  
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
   if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
       && type == TREE_TYPE (TREE_TYPE (subtype)))
@@ -11535,10 +12817,10 @@ ptr_difference_const (tree e1, tree e2, HOST_WIDE_INT *diff)
        toffset2 = fold_convert (type, toffset2);
 
       tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2);
-      if (!host_integerp (tdiff, 0))
+      if (!cst_and_fits_in_hwi (tdiff))
        return false;
 
-      *diff = tree_low_cst (tdiff, 0);
+      *diff = int_cst_value (tdiff);
     }
   else if (toffset1 || toffset2)
     {