OSDN Git Service

PR target/25168
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index a75d1a2..7cab3c4 100644 (file)
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /*@@ This file should be rewritten to use an arbitrary precision
   @@ representation for "struct tree_int_cst" and "struct tree_real_cst".
@@ -89,7 +89,6 @@ static tree negate_expr (tree);
 static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
 static tree associate_trees (tree, tree, enum tree_code, tree);
 static tree const_binop (enum tree_code, tree, tree, int);
-static enum tree_code invert_tree_comparison (enum tree_code, bool);
 static enum comparison_code comparison_to_compcode (enum tree_code);
 static enum tree_code compcode_to_comparison (enum comparison_code);
 static tree combine_comparisons (enum tree_code, enum tree_code,
@@ -133,7 +132,6 @@ 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);
 
 /* 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,
@@ -831,27 +829,51 @@ div_and_round_double (enum tree_code code, int uns,
   add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
   return overflow;
 }
+
+/* If ARG2 divides ARG1 with zero remainder, carries out the division
+   of type CODE and returns the quotient.
+   Otherwise returns NULL_TREE.  */
+
+static tree
+div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2)
+{
+  unsigned HOST_WIDE_INT int1l, int2l;
+  HOST_WIDE_INT int1h, int2h;
+  unsigned HOST_WIDE_INT quol, reml;
+  HOST_WIDE_INT quoh, remh;
+  tree type = TREE_TYPE (arg1);
+  int uns = TYPE_UNSIGNED (type);
+
+  int1l = TREE_INT_CST_LOW (arg1);
+  int1h = TREE_INT_CST_HIGH (arg1);
+  int2l = TREE_INT_CST_LOW (arg2);
+  int2h = TREE_INT_CST_HIGH (arg2);
+
+  div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
+                       &quol, &quoh, &reml, &remh);
+  if (remh != 0 || reml != 0)
+    return NULL_TREE;
+
+  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:
@@ -913,6 +935,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:
@@ -951,6 +975,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)
@@ -1002,6 +1036,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)
@@ -1092,6 +1133,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)
@@ -1282,7 +1345,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.  */
 
@@ -1371,6 +1435,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;
@@ -1403,6 +1469,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);
@@ -1427,7 +1495,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);
@@ -1483,6 +1551,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);
 
@@ -1512,6 +1595,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
@@ -1532,6 +1625,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);
@@ -1573,42 +1667,45 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
 
        case RDIV_EXPR:
          {
+           tree t1, t2, real, imag;
            tree magsquared
              = const_binop (PLUS_EXPR,
                             const_binop (MULT_EXPR, r2, r2, notrunc),
                             const_binop (MULT_EXPR, i2, i2, notrunc),
                             notrunc);
 
-           t = build_complex (type,
-                              const_binop
-                              (INTEGRAL_TYPE_P (TREE_TYPE (r1))
-                               ? TRUNC_DIV_EXPR : RDIV_EXPR,
-                               const_binop (PLUS_EXPR,
-                                            const_binop (MULT_EXPR, r1, r2,
-                                                         notrunc),
-                                            const_binop (MULT_EXPR, i1, i2,
-                                                         notrunc),
-                                            notrunc),
-                               magsquared, notrunc),
-                              const_binop
-                              (INTEGRAL_TYPE_P (TREE_TYPE (r1))
-                               ? TRUNC_DIV_EXPR : RDIV_EXPR,
-                               const_binop (MINUS_EXPR,
-                                            const_binop (MULT_EXPR, i1, r2,
-                                                         notrunc),
-                                            const_binop (MULT_EXPR, r1, i2,
-                                                         notrunc),
-                                            notrunc),
-                               magsquared, notrunc));
+           t1 = const_binop (PLUS_EXPR,
+                             const_binop (MULT_EXPR, r1, r2, notrunc),
+                             const_binop (MULT_EXPR, i1, i2, notrunc),
+                             notrunc);
+           t2 = const_binop (MINUS_EXPR,
+                             const_binop (MULT_EXPR, i1, r2, notrunc),
+                             const_binop (MULT_EXPR, r1, i2, notrunc),
+                             notrunc);
+
+           if (INTEGRAL_TYPE_P (TREE_TYPE (r1)))
+             {
+               real = const_binop (TRUNC_DIV_EXPR, t1, magsquared, notrunc);
+               imag = const_binop (TRUNC_DIV_EXPR, t2, magsquared, notrunc);
+             }
+           else
+             {
+               real = const_binop (RDIV_EXPR, t1, magsquared, notrunc);
+               imag = const_binop (RDIV_EXPR, t2, magsquared, notrunc);
+               if (!real || !imag)
+                 return NULL_TREE;
+             }
+
+           t = build_complex (type, real, imag);
          }
          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
@@ -1686,11 +1783,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)));
 }
@@ -1941,8 +2038,7 @@ fold_convert (tree type, tree arg)
          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);
@@ -1991,17 +2087,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
@@ -2089,7 +2185,7 @@ pedantic_non_lvalue (tree x)
    comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode
    as well: if reversing the comparison is unsafe, return ERROR_MARK.  */
 
-static enum tree_code
+enum tree_code
 invert_tree_comparison (enum tree_code code, bool honor_nans)
 {
   if (honor_nans && flag_trapping_math)
@@ -2140,6 +2236,10 @@ swap_tree_comparison (enum tree_code code)
     {
     case EQ_EXPR:
     case NE_EXPR:
+    case ORDERED_EXPR:
+    case UNORDERED_EXPR:
+    case LTGT_EXPR:
+    case UNEQ_EXPR:
       return code;
     case GT_EXPR:
       return LT_EXPR;
@@ -2149,6 +2249,14 @@ swap_tree_comparison (enum tree_code code)
       return GT_EXPR;
     case LE_EXPR:
       return GE_EXPR;
+    case UNGT_EXPR:
+      return UNLT_EXPR;
+    case UNGE_EXPR:
+      return UNLE_EXPR;
+    case UNLT_EXPR:
+      return UNGT_EXPR;
+    case UNLE_EXPR:
+      return UNGE_EXPR;
     default:
       gcc_unreachable ();
     }
@@ -2431,7 +2539,7 @@ operand_equal_p (tree arg0, tree arg1, unsigned int flags)
              v2 = TREE_CHAIN (v2);
            }
 
-         return 1;
+         return v1 == v2;
        }
 
       case COMPLEX_CST:
@@ -2527,8 +2635,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);
@@ -2985,9 +3096,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),
@@ -3009,7 +3129,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);
@@ -3076,6 +3196,46 @@ distribute_bit_expr (enum tree_code code, tree type, tree arg0, tree arg1)
   return fold_build2 (TREE_CODE (arg0), type, common,
                      fold_build2 (code, type, left, right));
 }
+
+/* Knowing that ARG0 and ARG1 are both RDIV_EXPRs, simplify a binary operation
+   with code CODE.  This optimization is unsafe.  */
+static tree
+distribute_real_division (enum tree_code code, tree type, tree arg0, tree arg1)
+{
+  bool mul0 = TREE_CODE (arg0) == MULT_EXPR;
+  bool mul1 = TREE_CODE (arg1) == MULT_EXPR;
+
+  /* (A / C) +- (B / C) -> (A +- B) / C.  */
+  if (mul0 == mul1
+      && operand_equal_p (TREE_OPERAND (arg0, 1),
+                      TREE_OPERAND (arg1, 1), 0))
+    return fold_build2 (mul0 ? MULT_EXPR : RDIV_EXPR, type,
+                       fold_build2 (code, type,
+                                    TREE_OPERAND (arg0, 0),
+                                    TREE_OPERAND (arg1, 0)),
+                       TREE_OPERAND (arg0, 1));
+
+  /* (A / C1) +- (A / C2) -> A * (1 / C1 +- 1 / C2).  */
+  if (operand_equal_p (TREE_OPERAND (arg0, 0),
+                      TREE_OPERAND (arg1, 0), 0)
+      && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+      && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
+    {
+      REAL_VALUE_TYPE r0, r1;
+      r0 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+      r1 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+      if (!mul0)
+       real_arithmetic (&r0, RDIV_EXPR, &dconst1, &r0);
+      if (!mul1)
+        real_arithmetic (&r1, RDIV_EXPR, &dconst1, &r1);
+      real_arithmetic (&r0, code, &r0, &r1);
+      return fold_build2 (MULT_EXPR, type,
+                         TREE_OPERAND (arg0, 0),
+                         build_real (type, r0));
+    }
+
+  return NULL_TREE;
+}
 \f
 /* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
    starting at BITPOS.  The field is unsigned if UNSIGNEDP is nonzero.  */
@@ -3247,7 +3407,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
@@ -3260,11 +3420,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),
@@ -3584,7 +3744,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)
     {
@@ -3657,7 +3817,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;
 
@@ -3671,7 +3831,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);
                }
            }
 
@@ -3681,10 +3841,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;
@@ -3693,13 +3853,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
@@ -3849,6 +4014,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);
@@ -3859,16 +4033,19 @@ 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, high);
+    return fold_build2 (LE_EXPR, type, exp,
+                       fold_convert (etype, high));
 
   if (high == 0)
-    return fold_build2 (GE_EXPR, type, exp, low);
+    return fold_build2 (GE_EXPR, type, exp,
+                       fold_convert (etype, low));
 
   if (operand_equal_p (low, high, 0))
-    return fold_build2 (EQ_EXPR, type, exp, low);
+    return fold_build2 (EQ_EXPR, type, exp,
+                       fold_convert (etype, low));
 
   if (integer_zerop (low))
     {
@@ -3908,12 +4085,13 @@ 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))
+  if (value != 0 && (!flag_wrapv || TREE_OVERFLOW (value))
+      && ! TYPE_UNSIGNED (etype))
     {
       tree utype, minv, maxv;
 
@@ -3924,6 +4102,11 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
        case INTEGER_TYPE:
        case ENUMERAL_TYPE:
        case CHAR_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);
          utype = lang_hooks.types.unsigned_type (etype);
          maxv = fold_convert (utype, TYPE_MAX_VALUE (etype));
          maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1,
@@ -3945,10 +4128,22 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
     }
 
   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);
+    {
+      /* 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 (INTEGRAL_TYPE_P (etype) && TREE_TYPE (etype))
+       {
+         etype = TREE_TYPE (etype);
+         exp = fold_convert (etype, exp);
+         low = fold_convert (etype, low);
+         value = fold_convert (etype, value);
+       }
+
+      return build_range_check (type,
+                               fold_build2 (MINUS_EXPR, etype, exp, low),
+                               1, build_int_cst (etype, 0), value);
+    }
 
   return 0;
 }
@@ -4254,7 +4449,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.
@@ -4611,14 +4806,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;
     }
 
@@ -4677,7 +4872,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
@@ -4687,7 +4882,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);
@@ -5418,26 +5613,32 @@ constant_boolean_node (int value, tree type)
 
 /* Return true if expr looks like an ARRAY_REF and set base and
    offset to the appropriate trees.  If there is no offset,
-   offset is set to NULL_TREE.  */
+   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)).  Offset will be the offset
+   in bytes to the base.  */
 
 static bool
 extract_array_ref (tree expr, tree *base, tree *offset)
 {
-  /* We have to be careful with stripping nops as with the
-     base type the meaning of the offset can change.  */
-  tree inner_expr = expr;
-  STRIP_NOPS (inner_expr);
   /* One canonical form is a PLUS_EXPR with the first
      argument being an ADDR_EXPR with a possible NOP_EXPR
      attached.  */
   if (TREE_CODE (expr) == PLUS_EXPR)
     {
       tree op0 = TREE_OPERAND (expr, 0);
+      tree inner_base, dummy1;
+      /* Strip NOP_EXPRs here because the C frontends and/or
+        folders present us (int *)&x.a + 4B possibly.  */
       STRIP_NOPS (op0);
-      if (TREE_CODE (op0) == ADDR_EXPR)
+      if (extract_array_ref (op0, &inner_base, &dummy1))
        {
-         *base = TREE_OPERAND (expr, 0);
-         *offset = TREE_OPERAND (expr, 1);
+         *base = inner_base;
+         if (dummy1 == NULL_TREE)
+           *offset = TREE_OPERAND (expr, 1);
+         else
+           *offset = fold_build2 (PLUS_EXPR, TREE_TYPE (expr),
+                                  dummy1, TREE_OPERAND (expr, 1));
          return true;
        }
     }
@@ -5446,21 +5647,35 @@ extract_array_ref (tree expr, tree *base, tree *offset)
      offset.  For other arguments to the ADDR_EXPR we assume
      zero offset and as such do not care about the ADDR_EXPR
      type and strip possible nops from it.  */
-  else if (TREE_CODE (inner_expr) == ADDR_EXPR)
+  else if (TREE_CODE (expr) == ADDR_EXPR)
     {
-      tree op0 = TREE_OPERAND (inner_expr, 0);
+      tree op0 = TREE_OPERAND (expr, 0);
       if (TREE_CODE (op0) == ARRAY_REF)
        {
-         *base = build_fold_addr_expr (TREE_OPERAND (op0, 0));
-         *offset = TREE_OPERAND (op0, 1);
+         tree idx = TREE_OPERAND (op0, 1);
+         *base = TREE_OPERAND (op0, 0);
+         *offset = fold_build2 (MULT_EXPR, TREE_TYPE (idx), idx,
+                                array_ref_element_size (op0)); 
        }
       else
        {
-         *base = inner_expr;
+         /* Handle array-to-pointer decay as &a.  */
+         if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE)
+           *base = TREE_OPERAND (expr, 0);
+         else
+           *base = expr;
          *offset = NULL_TREE;
        }
       return true;
     }
+  /* The next canonical form is a VAR_DECL with POINTER_TYPE.  */
+  else if (SSA_VAR_P (expr)
+          && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
+    {
+      *base = expr;
+      *offset = NULL_TREE;
+      return true;
+    }
 
   return false;
 }
@@ -5955,7 +6170,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));
        }
     }
 
@@ -6141,20 +6356,21 @@ 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
        || TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type))
       && (TREE_TYPE (arg1_unw) == shorter_type
          || (TREE_CODE (arg1_unw) == INTEGER_CST
-             && TREE_CODE (shorter_type) == INTEGER_TYPE
+             && (TREE_CODE (shorter_type) == INTEGER_TYPE
+                 || TREE_CODE (shorter_type) == BOOLEAN_TYPE)
              && int_fits_type_p (arg1_unw, shorter_type))))
     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
@@ -6258,55 +6474,80 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
 }
 
 /* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
-   step of the array.  ADDR is the address. MULT is the multiplicative expression.
+   step of the array.  Reconstructs s and delta in the case of s * delta
+   being an integer constant (and thus already folded).
+   ADDR is the address. MULT is the multiplicative expression.
    If the function succeeds, the new address expression is returned.  Otherwise
    NULL_TREE is returned.  */
 
 static tree
-try_move_mult_to_index (enum tree_code code, tree addr, tree mult)
+try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
 {
   tree s, delta, step;
-  tree arg0 = TREE_OPERAND (mult, 0), arg1 = TREE_OPERAND (mult, 1);
   tree ref = TREE_OPERAND (addr, 0), pref;
   tree ret, pos;
   tree itype;
 
-  STRIP_NOPS (arg0);
-  STRIP_NOPS (arg1);
-  
-  if (TREE_CODE (arg0) == INTEGER_CST)
+  /* Canonicalize op1 into a possibly non-constant delta
+     and an INTEGER_CST s.  */
+  if (TREE_CODE (op1) == MULT_EXPR)
     {
-      s = arg0;
-      delta = arg1;
+      tree arg0 = TREE_OPERAND (op1, 0), arg1 = TREE_OPERAND (op1, 1);
+
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+  
+      if (TREE_CODE (arg0) == INTEGER_CST)
+        {
+          s = arg0;
+          delta = arg1;
+        }
+      else if (TREE_CODE (arg1) == INTEGER_CST)
+        {
+          s = arg1;
+          delta = arg0;
+        }
+      else
+        return NULL_TREE;
     }
-  else if (TREE_CODE (arg1) == INTEGER_CST)
+  else if (TREE_CODE (op1) == INTEGER_CST)
     {
-      s = arg1;
-      delta = arg0;
+      delta = op1;
+      s = NULL_TREE;
     }
   else
-    return NULL_TREE;
+    {
+      /* Simulate we are delta * 1.  */
+      delta = op1;
+      s = integer_one_node;
+    }
 
   for (;; ref = TREE_OPERAND (ref, 0))
     {
       if (TREE_CODE (ref) == ARRAY_REF)
        {
-         step = array_ref_element_size (ref);
-
-         if (TREE_CODE (step) != INTEGER_CST)
+         itype = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (ref, 0)));
+         if (! itype)
            continue;
 
-         itype = TREE_TYPE (step);
-
-         /* If the type sizes do not match, we might run into problems
-            when one of them would overflow.  */
-         if (TYPE_PRECISION (itype) != TYPE_PRECISION (TREE_TYPE (s)))
+         step = array_ref_element_size (ref);
+         if (TREE_CODE (step) != INTEGER_CST)
            continue;
 
-         if (!operand_equal_p (step, fold_convert (itype, s), 0))
-           continue;
+         if (s)
+           {
+             if (! tree_int_cst_equal (step, s))
+                continue;
+           }
+         else
+           {
+             /* Try if delta is a multiple of step.  */
+             tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, delta, step);
+             if (! tmp)
+               continue;
+             delta = tmp;
+           }
 
-         delta = fold_convert (itype, delta);
          break;
        }
 
@@ -6329,10 +6570,11 @@ try_move_mult_to_index (enum tree_code code, tree addr, tree mult)
     }
 
   TREE_OPERAND (pos, 1) = fold_build2 (code, itype,
-                                      TREE_OPERAND (pos, 1),
-                                      delta);
+                                      fold_convert (itype,
+                                                    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);
 }
 
 
@@ -6380,298 +6622,102 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
   return fold_build2 (GE_EXPR, type, a, y);
 }
 
-/* Fold complex addition when both components are accessible by parts.
-   Return non-null if successful.  CODE should be PLUS_EXPR for addition,
-   or MINUS_EXPR for subtraction.  */
+/* Fold a sum or difference of at least one multiplication.
+   Returns the folded tree or NULL if no simplification could be made.  */
 
 static tree
-fold_complex_add (tree type, tree ac, tree bc, enum tree_code code)
-{
-  tree ar, ai, br, bi, rr, ri, inner_type;
-
-  if (TREE_CODE (ac) == COMPLEX_EXPR)
-    ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
-  else if (TREE_CODE (ac) == COMPLEX_CST)
-    ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
-  else
-    return NULL;
-
-  if (TREE_CODE (bc) == COMPLEX_EXPR)
-    br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
-  else if (TREE_CODE (bc) == COMPLEX_CST)
-    br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
-  else
-    return NULL;
-
-  inner_type = TREE_TYPE (type);
-
-  rr = fold_build2 (code, inner_type, ar, br); 
-  ri = fold_build2 (code, inner_type, ai, bi); 
-
-  return fold_build2 (COMPLEX_EXPR, type, rr, ri);
-}
-
-/* Perform some simplifications of complex multiplication when one or more
-   of the components are constants or zeros.  Return non-null if successful.  */
-
-tree
-fold_complex_mult_parts (tree type, tree ar, tree ai, tree br, tree bi)
+fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
 {
-  tree rr, ri, inner_type, zero;
-  bool ar0, ai0, br0, bi0, bi1;
+  tree arg00, arg01, arg10, arg11;
+  tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
 
-  inner_type = TREE_TYPE (type);
-  zero = NULL;
+  /* (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.  */
 
-  if (SCALAR_FLOAT_TYPE_P (inner_type))
+  if (TREE_CODE (arg0) == MULT_EXPR)
     {
-      ar0 = ai0 = br0 = bi0 = bi1 = false;
-
-      /* We're only interested in +0.0 here, thus we don't use real_zerop.  */
-
-      if (TREE_CODE (ar) == REAL_CST
-         && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ar), dconst0))
-       ar0 = true, zero = ar;
-
-      if (TREE_CODE (ai) == REAL_CST
-         && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ai), dconst0))
-       ai0 = true, zero = ai;
-
-      if (TREE_CODE (br) == REAL_CST
-         && REAL_VALUES_IDENTICAL (TREE_REAL_CST (br), dconst0))
-       br0 = true, zero = br;
-
-      if (TREE_CODE (bi) == REAL_CST)
-       {
-         if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst0))
-           bi0 = true, zero = bi;
-         else if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst1))
-           bi1 = true;
-       }
+      arg00 = TREE_OPERAND (arg0, 0);
+      arg01 = TREE_OPERAND (arg0, 1);
     }
   else
     {
-      ar0 = integer_zerop (ar);
-      if (ar0)
-       zero = ar;
-      ai0 = integer_zerop (ai);
-      if (ai0)
-       zero = ai;
-      br0 = integer_zerop (br);
-      if (br0)
-       zero = br;
-      bi0 = integer_zerop (bi);
-      if (bi0)
-       {
-         zero = bi;
-         bi1 = false;
-       }
+      arg00 = arg0;
+      if (!FLOAT_TYPE_P (type))
+       arg01 = build_int_cst (type, 1);
       else
-       bi1 = integer_onep (bi);
-    }
-
-  /* We won't optimize anything below unless something is zero.  */
-  if (zero == NULL)
-    return NULL;
-
-  if (ai0 && br0 && bi1)
-    {
-      rr = zero;
-      ri = ar;
-    }
-  else if (ai0 && bi0)
-    {
-      rr = fold_build2 (MULT_EXPR, inner_type, ar, br);
-      ri = zero;
-    }
-  else if (ai0 && br0)
-    {
-      rr = zero;
-      ri = fold_build2 (MULT_EXPR, inner_type, ar, bi);
+       arg01 = build_real (type, dconst1);
     }
-  else if (ar0 && bi0)
-    {
-      rr = zero;
-      ri = fold_build2 (MULT_EXPR, inner_type, ai, br);
-    }
-  else if (ar0 && br0)
-    {
-      rr = fold_build2 (MULT_EXPR, inner_type, ai, bi);
-      rr = fold_build1 (NEGATE_EXPR, inner_type, rr);
-      ri = zero;
-    }
-  else if (bi0)
-    {
-      rr = fold_build2 (MULT_EXPR, inner_type, ar, br);
-      ri = fold_build2 (MULT_EXPR, inner_type, ai, br);
-    }
-  else if (ai0)
-    {
-      rr = fold_build2 (MULT_EXPR, inner_type, ar, br);
-      ri = fold_build2 (MULT_EXPR, inner_type, ar, bi);
-    }
-  else if (br0)
-    {
-      rr = fold_build2 (MULT_EXPR, inner_type, ai, bi);
-      rr = fold_build1 (NEGATE_EXPR, inner_type, rr);
-      ri = fold_build2 (MULT_EXPR, inner_type, ar, bi);
-    }
-  else if (ar0)
-    {
-      rr = fold_build2 (MULT_EXPR, inner_type, ai, bi);
-      rr = fold_build1 (NEGATE_EXPR, inner_type, rr);
-      ri = fold_build2 (MULT_EXPR, inner_type, ai, br);
-    }
-  else
-    return NULL;
-
-  return fold_build2 (COMPLEX_EXPR, type, rr, ri);
-}
-
-static tree
-fold_complex_mult (tree type, tree ac, tree bc)
-{
-  tree ar, ai, br, bi;
-
-  if (TREE_CODE (ac) == COMPLEX_EXPR)
-    ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
-  else if (TREE_CODE (ac) == COMPLEX_CST)
-    ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
-  else
-    return NULL;
-
-  if (TREE_CODE (bc) == COMPLEX_EXPR)
-    br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
-  else if (TREE_CODE (bc) == COMPLEX_CST)
-    br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
-  else
-    return NULL;
-
-  return fold_complex_mult_parts (type, ar, ai, br, bi);
-}
-
-/* Perform some simplifications of complex division when one or more of
-   the components are constants or zeros.  Return non-null if successful.  */
-
-tree
-fold_complex_div_parts (tree type, tree ar, tree ai, tree br, tree bi,
-                       enum tree_code code)
-{
-  tree rr, ri, inner_type, zero;
-  bool ar0, ai0, br0, bi0, bi1;
-
-  inner_type = TREE_TYPE (type);
-  zero = NULL;
-
-  if (SCALAR_FLOAT_TYPE_P (inner_type))
+  if (TREE_CODE (arg1) == MULT_EXPR)
     {
-      ar0 = ai0 = br0 = bi0 = bi1 = false;
-
-      /* We're only interested in +0.0 here, thus we don't use real_zerop.  */
-
-      if (TREE_CODE (ar) == REAL_CST
-         && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ar), dconst0))
-       ar0 = true, zero = ar;
-
-      if (TREE_CODE (ai) == REAL_CST
-         && REAL_VALUES_IDENTICAL (TREE_REAL_CST (ai), dconst0))
-       ai0 = true, zero = ai;
-
-      if (TREE_CODE (br) == REAL_CST
-         && REAL_VALUES_IDENTICAL (TREE_REAL_CST (br), dconst0))
-       br0 = true, zero = br;
-
-      if (TREE_CODE (bi) == REAL_CST)
-       {
-         if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst0))
-           bi0 = true, zero = bi;
-         else if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (bi), dconst1))
-           bi1 = true;
-       }
+      arg10 = TREE_OPERAND (arg1, 0);
+      arg11 = TREE_OPERAND (arg1, 1);
     }
   else
     {
-      ar0 = integer_zerop (ar);
-      if (ar0)
-       zero = ar;
-      ai0 = integer_zerop (ai);
-      if (ai0)
-       zero = ai;
-      br0 = integer_zerop (br);
-      if (br0)
-       zero = br;
-      bi0 = integer_zerop (bi);
-      if (bi0)
-       {
-         zero = bi;
-         bi1 = false;
+      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
-       bi1 = integer_onep (bi);
-    }
-
-  /* We won't optimize anything below unless something is zero.  */
-  if (zero == NULL)
-    return NULL;
+       maybe_same = arg11;
 
-  if (ai0 && bi0)
-    {
-      rr = fold_build2 (code, inner_type, ar, br);
-      ri = zero;
-    }
-  else if (ai0 && br0)
-    {
-      rr = zero;
-      ri = fold_build2 (code, inner_type, ar, bi);
-      ri = fold_build1 (NEGATE_EXPR, inner_type, ri);
-    }
-  else if (ar0 && bi0)
-    {
-      rr = zero;
-      ri = fold_build2 (code, inner_type, ai, br);
-    }
-  else if (ar0 && br0)
-    {
-      rr = fold_build2 (code, inner_type, ai, bi);
-      ri = zero;
-    }
-  else if (bi0)
-    {
-      rr = fold_build2 (code, inner_type, ar, br);
-      ri = fold_build2 (code, inner_type, ai, br);
-    }
-  else if (br0)
-    {
-      rr = fold_build2 (code, inner_type, ai, bi);
-      ri = fold_build2 (code, inner_type, ar, bi);
-      ri = fold_build1 (NEGATE_EXPR, inner_type, ri);
+      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;
+       }
     }
-  else
-    return NULL;
-
-  return fold_build2 (COMPLEX_EXPR, type, rr, ri);
-}
-
-static tree
-fold_complex_div (tree type, tree ac, tree bc, enum tree_code code)
-{
-  tree ar, ai, br, bi;
-
-  if (TREE_CODE (ac) == COMPLEX_EXPR)
-    ar = TREE_OPERAND (ac, 0), ai = TREE_OPERAND (ac, 1);
-  else if (TREE_CODE (ac) == COMPLEX_CST)
-    ar = TREE_REALPART (ac), ai = TREE_IMAGPART (ac);
-  else
-    return NULL;
 
-  if (TREE_CODE (bc) == COMPLEX_EXPR)
-    br = TREE_OPERAND (bc, 0), bi = TREE_OPERAND (bc, 1);
-  else if (TREE_CODE (bc) == COMPLEX_CST)
-    br = TREE_REALPART (bc), bi = TREE_IMAGPART (bc);
-  else
-    return NULL;
+  if (same)
+    return fold_build2 (MULT_EXPR, type,
+                       fold_build2 (code, type,
+                                    fold_convert (type, alt0),
+                                    fold_convert (type, alt1)),
+                       fold_convert (type, same));
 
-  return fold_complex_div_parts (type, ar, ai, br, bi, code);
+  return NULL_TREE;
 }
 
 /* Fold a unary expression of code CODE and type TYPE with operand
@@ -6691,9 +6737,11 @@ fold_unary (enum tree_code code, tree type, tree op0)
   arg0 = op0;
   if (arg0)
     {
-      if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
+      if (code == NOP_EXPR || code == CONVERT_EXPR
+         || code == FLOAT_EXPR || code == ABS_EXPR)
        {
-         /* Don't use STRIP_NOPS, because signedness of argument type matters.  */
+         /* Don't use STRIP_NOPS, because signedness of argument type
+            matters.  */
          STRIP_SIGN_NOPS (arg0);
        }
       else
@@ -6789,6 +6837,12 @@ fold_unary (enum tree_code code, tree type, tree op0)
     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
@@ -6876,6 +6930,29 @@ fold_unary (enum tree_code code, tree type, tree op0)
            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.  */
@@ -6972,10 +7049,6 @@ fold_unary (enum tree_code code, tree type, tree op0)
     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;
 
     case ABS_EXPR:
@@ -6993,7 +7066,8 @@ fold_unary (enum tree_code code, tree type, tree op0)
                                                    TREE_TYPE (targ0),
                                                    targ0));
        }
-      else if (tree_expr_nonnegative_p (arg0))
+      /* 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.  */
@@ -7121,80 +7195,57 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
   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;
-
   gcc_assert (IS_EXPR_CODE_CLASS (kind)
-             && TREE_CODE_LENGTH (code) == 2);
+             && TREE_CODE_LENGTH (code) == 2
+             && op0 != NULL_TREE
+             && op1 != NULL_TREE);
 
   arg0 = op0;
   arg1 = op1;
 
-  if (arg0)
-    {
-      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);
+  /* 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.
 
-      if (TREE_CODE (arg0) == COMPLEX_CST)
-       subop = TREE_REALPART (arg0);
-      else
-       subop = arg0;
+     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 (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;
+  if (kind == tcc_comparison)
+    {
+      STRIP_SIGN_NOPS (arg0);
+      STRIP_SIGN_NOPS (arg1);
     }
-
-  if (arg1)
+  else
     {
-      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 (arg1);
-      else
-       STRIP_NOPS (arg1);
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+    }
 
-      if (TREE_CODE (arg1) == COMPLEX_CST)
-       subop = TREE_REALPART (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
-       subop = arg1;
+       tem = NULL_TREE;
 
-      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;
+      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
@@ -7203,9 +7254,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       && 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).
+  /* 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
@@ -7245,26 +7294,18 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       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_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));
+                      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,
-                                   arg0, TREE_OPERAND (arg1, 1)));
+                                   op0, TREE_OPERAND (arg1, 1)));
 
       if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
        {
@@ -7305,9 +7346,13 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && integer_onep (arg1))
        return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
 
-      if (TREE_CODE (type) == COMPLEX_TYPE)
-       {
-         tem = fold_complex_add (type, arg0, arg1, PLUS_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))
+        {
+         tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
          if (tem)
            return tem;
        }
@@ -7373,86 +7418,20 @@ 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.  */
-         if (TREE_CODE (arg0) == ADDR_EXPR
-             && TREE_CODE (arg1) == MULT_EXPR)
+         if (TREE_CODE (arg0) == ADDR_EXPR)
            {
              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
-                  && TREE_CODE (arg0) == MULT_EXPR)
+         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
@@ -7476,62 +7455,18 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                    fold_convert (type, tem));
            }
 
+          if (flag_unsafe_math_optimizations
+             && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
+             && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
+             && (tem = distribute_real_division (code, type, arg0, arg1)))
+           return tem;
+
          /* Convert x+x into x*2.0.  */
          if (operand_equal_p (arg0, arg1, 0)
              && SCALAR_FLOAT_TYPE_P (type))
            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
@@ -7641,8 +7576,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;
@@ -7716,18 +7650,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:
@@ -7753,16 +7675,9 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && integer_all_onesp (arg0))
        return fold_build1 (BIT_NOT_EXPR, type, arg1);
 
-      if (TREE_CODE (type) == COMPLEX_TYPE)
-       {
-         tem = fold_complex_add (type, arg0, arg1, MINUS_EXPR);
-         if (tem)
-           return tem;
-       }
-
       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));
@@ -7810,7 +7725,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.
@@ -7824,13 +7739,15 @@ 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
                   ||  REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
              || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
-       return fold_build2 (PLUS_EXPR, type, arg0, negate_expr (arg1));
+       return fold_build2 (PLUS_EXPR, type,
+                           fold_convert (type, arg0),
+                           fold_convert (type, negate_expr (arg1)));
 
       /* Try folding difference of addresses.  */
       {
@@ -7866,34 +7783,28 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       /* 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.  */
-      if (TREE_CODE (arg0) == ADDR_EXPR
-         && TREE_CODE (arg1) == MULT_EXPR)
+      if (TREE_CODE (arg0) == ADDR_EXPR)
        {
          tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1);
          if (tem)
-           return fold_convert (type, fold (tem));
+           return fold_convert (type, tem);
        }
 
-      if (TREE_CODE (arg0) == MULT_EXPR
-         && TREE_CODE (arg1) == MULT_EXPR
+      if (flag_unsafe_math_optimizations
+         && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
+         && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
+         && (tem = distribute_real_division (code, type, arg0, arg1)))
+       return tem;
+
+      /* 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;
@@ -7909,13 +7820,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                            negate_expr (arg0),
                            TREE_OPERAND (arg1, 0));
 
-      if (TREE_CODE (type) == COMPLEX_TYPE)
-       {
-         tem = fold_complex_mult (type, arg0, arg1);
-         if (tem)
-           return tem;
-       }
-
       if (! FLOAT_TYPE_P (type))
        {
          if (integer_zerop (arg1))
@@ -8235,6 +8139,54 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          goto bit_ior;
        }
 
+      /* (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;
+       }
+
+      /* (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;
+       }
+
+      /* 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;
+       }
+
+      /* 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)
@@ -8305,6 +8257,17 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && real_zerop (arg1))
        return NULL_TREE;
 
+      /* Optimize A / A to 1.0 if we don't care about
+        NaNs or Infinities.  */
+      if (! 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);
+       }
+
       /* (-A) / (-B) -> A / B  */
       if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
        return fold_build2 (RDIV_EXPR, type,
@@ -8344,7 +8307,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
                {
                  tem = build_real (type, r);
-                 return fold_build2 (MULT_EXPR, type, arg0, tem);
+                 return fold_build2 (MULT_EXPR, type,
+                                     fold_convert (type, arg0), tem);
                }
            }
        }
@@ -8376,43 +8340,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                TREE_OPERAND (arg1, 0));
        }
 
-      if (TREE_CODE (type) == COMPLEX_TYPE)
-       {
-         tem = fold_complex_div (type, arg0, arg1, code);
-         if (tem)
-           return tem;
-       }
-
-      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);
@@ -8450,6 +8377,53 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                }
            }
 
+         /* 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));
+
+             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);
+
+                 if (cosfn != NULL_TREE)
+                   return build_function_call_expr (cosfn,
+                                                    TREE_OPERAND (arg0, 1));
+               }
+           }
+
+         /* 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));
+
+             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);
+
+                 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);
+                   }
+               }
+           }
+
          /* Optimize pow(x,c)/x as pow(x,c-1).  */
          if (fcode0 == BUILT_IN_POW
              || fcode0 == BUILT_IN_POWF
@@ -8473,8 +8447,34 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  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);
+           }
+
+         /* 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);
+           }
        }
-      goto binary;
+      return NULL_TREE;
 
     case TRUNC_DIV_EXPR:
     case ROUND_DIV_EXPR:
@@ -8492,6 +8492,19 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && TREE_INT_CST_HIGH (arg1) == -1)
        return fold_convert (type, negate_expr (arg0));
 
+      /* 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));
+
       /* If arg0 is a multiple of arg1, then rewrite to the fastest div
         operation, EXACT_DIV_EXPR.
 
@@ -8506,13 +8519,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
        return fold_convert (type, tem);
 
-      if (TREE_CODE (type) == COMPLEX_TYPE)
-       {
-         tem = fold_complex_div (type, arg0, arg1, code);
-         if (tem)
-           return tem;
-       }
-      goto binary;
+      return NULL_TREE;
 
     case CEIL_MOD_EXPR:
     case FLOOR_MOD_EXPR:
@@ -8540,11 +8547,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && TREE_INT_CST_HIGH (arg1) == -1)
        return omit_one_operand (type, integer_zero_node, arg0);
 
-      /* Optimize unsigned TRUNC_MOD_EXPR by a power of two into a
-        BIT_AND_EXPR, i.e. "X % C" into "X & C2".  */
-      if (code == TRUNC_MOD_EXPR
-         && TYPE_UNSIGNED (type)
-         && integer_pow2p (arg1))
+      /* 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;
@@ -8592,7 +8599,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
        return fold_convert (type, tem);
 
-      goto binary;
+      return NULL_TREE;
 
     case LROTATE_EXPR:
     case RROTATE_EXPR:
@@ -8617,6 +8624,58 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
         don't try to compute it in the compiler.  */
       if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
        return NULL_TREE;
+
+      /* 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));
+
+         /* 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;
+           }
+
+         return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                             build_int_cst (type, low));
+       }
+
+      /* 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 (low0 == low1)
+           {
+             arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
+
+             lshift = build_int_cst (type, -1);
+             lshift = int_const_binop (code, lshift, arg1, 0);
+
+             return fold_build2 (BIT_AND_EXPR, type, arg00, lshift);
+           }
+       }
+
       /* Rewrite an LROTATE_EXPR by a constant into an
         RROTATE_EXPR by a new constant.  */
       if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
@@ -8654,7 +8713,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              == (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
        return TREE_OPERAND (arg0, 0);
 
-      goto binary;
+      return NULL_TREE;
 
     case MIN_EXPR:
       if (operand_equal_p (arg0, arg1, 0))
@@ -8714,11 +8773,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && !TREE_SIDE_EFFECTS (arg1))
        {
          tem = fold_to_nonsharp_ineq_using_bound (arg0, arg1);
-         if (tem)
+         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)
+         if (tem && !operand_equal_p (tem, arg1, 0))
            return fold_build2 (code, type, arg0, tem);
        }
 
@@ -8856,16 +8915,43 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
     case LT_EXPR:
     case GT_EXPR:
     case LE_EXPR:
-    case GE_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);
 
+      /*  ~a != C becomes a != ~C where C is a constant.  Likewise for ==.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR && TREE_CODE (arg1) == INTEGER_CST
+         && (code == NE_EXPR || code == EQ_EXPR))
+       return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+                           fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), 
+                                        arg1));
+       
+      /* 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));
+
+      /* 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);
+
+      /* 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);
+
       /* 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
-         && DECL_P (TREE_OPERAND (arg0, 0))
+         && 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);
@@ -8875,20 +8961,34 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
         have access to attributes for externs), then we know the result.  */
       if ((code == EQ_EXPR || code == NE_EXPR)
          && TREE_CODE (arg0) == ADDR_EXPR
-         && DECL_P (TREE_OPERAND (arg0, 0))
+         && 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
-         && DECL_P (TREE_OPERAND (arg1, 0))
+         && 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)))
-       return constant_boolean_node (operand_equal_p (arg0, arg1, 0)
-                                     ? code == EQ_EXPR : code != EQ_EXPR,
-                                     type);
+       {
+         /* We know that we're looking at the address of two
+            non-weak, unaliased, static _DECL nodes.
+
+            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 a comparison of two exprs that look like an
         ARRAY_REF of the same object, then we can fold this to a
@@ -8901,19 +9001,21 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              && 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))
                {
-                 offset0 = integer_zero_node;
-                 offset1 = integer_zero_node;
+                 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);
                }
-             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);
-
-             if (TREE_TYPE (offset0) == TREE_TYPE (offset1))
-               return fold_build2 (code, type, offset0, offset1);
            }
        }
 
@@ -8988,6 +9090,30 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            }
        }
 
+      /* 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);
@@ -9162,12 +9288,16 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          switch (code)
            {
            case GE_EXPR:
-             arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-             return fold_build2 (GT_EXPR, type, arg0, arg1);
+             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));
 
            case LT_EXPR:
-             arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-             return fold_build2 (LE_EXPR, type, arg0, arg1);
+             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));
 
            default:
              break;
@@ -9281,7 +9411,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  return omit_one_operand (type, integer_one_node, arg0);
 
                case GT_EXPR:
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+                 return fold_build2 (NE_EXPR, type, op0, op1);
 
                default:
                  break;
@@ -9315,10 +9445,9 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                    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)));
+                   return fold_build2 (code == LE_EXPR ? GE_EXPR: LT_EXPR,
+                                       type, fold_convert (st0, arg0),
+                                       build_int_cst (st1, 0));
                  }
              }
          }
@@ -9541,7 +9670,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        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));
+                      build_int_cst (TREE_TYPE (arg0), 0));
 
       else if ((code == LT_EXPR || code == GE_EXPR)
               && TYPE_UNSIGNED (TREE_TYPE (arg0))
@@ -9555,7 +9684,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
                                        TREE_OPERAND (TREE_OPERAND (arg1, 0),
                                                      1))),
-                 fold_convert (TREE_TYPE (arg0), integer_zero_node));
+                 build_int_cst (TREE_TYPE (arg0), 0));
 
       /* Simplify comparison of something with itself.  (For IEEE
         floating-point, we can only do some of these simplifications.)  */
@@ -9708,32 +9837,25 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            return t1;
        }
 
-      /* If this is a comparison of complex values and either or both sides
-        are a COMPLEX_EXPR or COMPLEX_CST, it is best to split up the
-        comparisons and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR.
-        This may prevent needless evaluations.  */
-      if ((code == EQ_EXPR || code == NE_EXPR)
-         && TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
-         && (TREE_CODE (arg0) == COMPLEX_EXPR
-             || TREE_CODE (arg1) == COMPLEX_EXPR
-             || TREE_CODE (arg0) == COMPLEX_CST
-             || TREE_CODE (arg1) == COMPLEX_CST))
-       {
-         tree subtype = TREE_TYPE (TREE_TYPE (arg0));
-         tree real0, imag0, real1, imag1;
-
-         arg0 = save_expr (arg0);
-         arg1 = save_expr (arg1);
-         real0 = fold_build1 (REALPART_EXPR, subtype, arg0);
-         imag0 = fold_build1 (IMAGPART_EXPR, subtype, arg0);
-         real1 = fold_build1 (REALPART_EXPR, subtype, arg1);
-         imag1 = fold_build1 (IMAGPART_EXPR, subtype, arg1);
-
-         return fold_build2 ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
-                              : TRUTH_ORIF_EXPR),
-                             type,
-                             fold_build2 (code, type, real0, real1),
-                             fold_build2 (code, type, imag0, imag1));
+      /* 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));
+           }
        }
 
       /* Optimize comparisons of strlen vs zero to a compare of the
@@ -9755,11 +9877,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              && (arglist = TREE_OPERAND (arg0, 1))
              && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
              && ! TREE_CHAIN (arglist))
-           return fold_build2 (code, type,
-                               build1 (INDIRECT_REF, char_type_node,
-                                       TREE_VALUE (arglist)),
-                               fold_convert (char_type_node,
-                                             integer_zero_node));
+           {
+             tree iref = build_fold_indirect_ref (TREE_VALUE (arglist));
+             return fold_build2 (code, type, iref,
+                                 build_int_cst (TREE_TYPE (iref), 0));
+           }
        }
 
       /* We can fold X/C1 op C2 where C1 and C2 are integer constants
@@ -9778,10 +9900,12 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        }
 
       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);
+        {
+         tree res = constant_boolean_node (code==NE_EXPR, type);
+         return omit_one_operand (type, res, arg0);
+       }
 
       t1 = fold_relational_const (code, type, arg0, arg1);
       return t1 == NULL_TREE ? NULL_TREE : t1;
@@ -9860,15 +9984,53 @@ 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;
 
+    case ASSERT_EXPR:
+      /* An ASSERT_EXPR should never be passed to fold_binary.  */
+      gcc_unreachable ();
+
     default:
       return NULL_TREE;
     } /* switch (code) */
 }
 
+/* Callback for walk_tree, looking for LABEL_EXPR.
+   Returns tree TP if it is LABEL_EXPR. Otherwise it returns NULL_TREE.
+   Do not check the sub-tree of GOTO_EXPR.  */
+
+static tree
+contains_label_1 (tree *tp,
+                  int *walk_subtrees,
+                  void *data ATTRIBUTE_UNUSED)
+{
+  switch (TREE_CODE (*tp))
+    {
+    case LABEL_EXPR:
+      return *tp;
+    case GOTO_EXPR:
+      *walk_subtrees = 0;
+    /* no break */
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Checks whether the sub-tree ST contains a label LABEL_EXPR which is
+   accessible from outside the sub-tree. Returns NULL_TREE if no
+   addressable label is found.  */
+
+static bool
+contains_label_p (tree st)
+{
+  return (walk_tree (&st, contains_label_1 , NULL, NULL) != NULL_TREE);
+}
+
 /* Fold a ternary expression of code CODE and type TYPE with operands
    OP0, OP1, and OP2.  Return the folded expression if folding is
    successful.  Otherwise, return NULL_TREE.  */
@@ -9911,9 +10073,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;
 
@@ -9922,12 +10086,16 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
         so all simple results must be passed through pedantic_non_lvalue.  */
       if (TREE_CODE (arg0) == INTEGER_CST)
        {
+         tree unused_op = integer_zerop (arg0) ? op1 : op2;
          tem = integer_zerop (arg0) ? op2 : op1;
          /* Only optimize constant conditions when the selected branch
             has the same type as the COND_EXPR.  This avoids optimizing
-            away "c ? x : throw", where the throw has a void type.  */
-         if (! VOID_TYPE_P (TREE_TYPE (tem))
-             || VOID_TYPE_P (type))
+             away "c ? x : throw", where the throw has a void type.
+             Avoid throwing away that operand which contains label.  */
+          if ((!TREE_SIDE_EFFECTS (unused_op)
+               || !contains_label_p (unused_op))
+              && (! VOID_TYPE_P (TREE_TYPE (tem))
+                  || VOID_TYPE_P (type)))
            return pedantic_non_lvalue (tem);
          return NULL_TREE;
        }
@@ -9967,7 +10135,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
@@ -10076,12 +10245,32 @@ 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)))
+       return fold_builtin (TREE_OPERAND (op0, 0), op1, false);
+      return NULL_TREE;
+
+    case BIT_FIELD_REF:
+      if (TREE_CODE (arg0) == VECTOR_CST
+         && type == TREE_TYPE (TREE_TYPE (arg0))
+         && host_integerp (arg1, 1)
+         && host_integerp (op2, 1))
        {
-         tree fndecl = TREE_OPERAND (op0, 0);
-         tree arglist = op1;
-         tree tmp = fold_builtin (fndecl, arglist, false);
-         if (tmp)
-           return tmp;
+         unsigned HOST_WIDE_INT width = tree_low_cst (arg1, 1);
+         unsigned HOST_WIDE_INT idx = tree_low_cst (op2, 1);
+
+         if (width != 0
+             && simple_cst_equal (arg1, TYPE_SIZE (type)) == 1
+             && (idx % width) == 0
+             && (idx = idx / width)
+                < TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))
+           {
+             tree elements = TREE_VECTOR_CST_ELTS (arg0);
+             while (idx-- > 0 && elements)
+               elements = TREE_CHAIN (elements);
+             if (elements)
+               return TREE_VALUE (elements);
+             else
+               return fold_convert (type, integer_zero_node);
+           }
        }
       return NULL_TREE;
 
@@ -10147,21 +10336,6 @@ fold (tree expr)
     case CONST_DECL:
       return fold (DECL_INITIAL (t));
 
-    case ASSERT_EXPR:
-      {
-       /* Given ASSERT_EXPR <Y, COND>, return Y if COND can be folded
-          to boolean_true_node.  If COND folds to boolean_false_node,
-          return ASSERT_EXPR <Y, 0>.  Otherwise, return the original
-          expression.  */
-       tree c = fold (ASSERT_EXPR_COND (t));
-       if (c == boolean_true_node)
-         return ASSERT_EXPR_VAR (t);
-       else if (c == boolean_false_node)
-         return build (ASSERT_EXPR, TREE_TYPE (t), ASSERT_EXPR_VAR (t), c);
-       else
-         return t;
-      }
-
     default:
       return t;
     } /* switch (code) */
@@ -10233,12 +10407,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)];
+  char buf[sizeof (struct tree_function_decl)];
   int i, len;
+  
+recursive_label:
 
   gcc_assert ((sizeof (struct tree_exp) + 5 * sizeof (tree)
-              <= sizeof (struct tree_decl))
-             && sizeof (struct tree_type) <= sizeof (struct tree_decl));
+              <= 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);
@@ -10256,11 +10432,13 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
     }
   else if (TREE_CODE_CLASS (code) == tcc_type
           && (TYPE_POINTER_TO (expr) || TYPE_REFERENCE_TO (expr)
-              || TYPE_CACHED_VALUES_P (expr)))
+              || TYPE_CACHED_VALUES_P (expr)
+              || TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)))
     {
       /* Allow these fields to be modified.  */
       memcpy (buf, expr, tree_size (expr));
       expr = (tree) buf;
+      TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) = 0;
       TYPE_POINTER_TO (expr) = NULL;
       TYPE_REFERENCE_TO (expr) = NULL;
       if (TYPE_CACHED_VALUES_P (expr))
@@ -10272,7 +10450,8 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
   md5_process_bytes (expr, tree_size (expr), ctx);
   fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
   if (TREE_CODE_CLASS (code) != tcc_type
-      && TREE_CODE_CLASS (code) != tcc_declaration)
+      && TREE_CODE_CLASS (code) != tcc_declaration
+      && code != TREE_LIST)
     fold_checksum_tree (TREE_CHAIN (expr), ctx, ht);
   switch (TREE_CODE_CLASS (code))
     {
@@ -10300,6 +10479,8 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
        case TREE_LIST:
          fold_checksum_tree (TREE_PURPOSE (expr), ctx, ht);
          fold_checksum_tree (TREE_VALUE (expr), ctx, ht);
+         expr = TREE_CHAIN (expr);
+         goto recursive_label;
          break;
        case TREE_VEC:
          for (i = 0; i < TREE_VEC_LENGTH (expr); ++i)
@@ -10320,17 +10501,25 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
        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)
@@ -10365,13 +10554,35 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
    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
@@ -10380,13 +10591,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
@@ -10395,43 +10645,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;
 
-  return build3 (code, type, op0, op1, op2);
+  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);
+
+  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);
 
-  result = fold (expr);
+  END_FOLD_INIT;
+  return result;
+}
+
+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.
 
@@ -10550,10 +10886,17 @@ 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 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;
@@ -10609,6 +10952,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:
@@ -10620,19 +10972,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:
       {
@@ -10661,28 +11015,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);
@@ -10721,84 +11053,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
            }
       }
 
@@ -10818,7 +11143,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);
@@ -10830,8 +11155,7 @@ tree_expr_nonzero_p (tree t)
   switch (TREE_CODE (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
@@ -10879,7 +11203,7 @@ tree_expr_nonzero_p (tree t)
          return false;
 
        /* Weak declarations may link to NULL.  */
-       if (DECL_P (base))
+       if (VAR_OR_FUNCTION_DECL_P (base))
          return !DECL_WEAK (base);
 
        /* Constants are never weak.  */
@@ -10926,6 +11250,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;
     }
@@ -11290,14 +11617,14 @@ build_fold_addr_expr (tree t)
   return build_fold_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
 }
 
-/* Given a pointer value T, return a simplified version of an indirection
-   through T, or NULL_TREE if no simplification is possible.  */
+/* Given a pointer value OP0 and a type TYPE, return a simplified version
+   of an indirection through OP0, or NULL_TREE if no simplification is
+   possible.  */
 
-static tree
-fold_indirect_ref_1 (tree t)
+tree
+fold_indirect_ref_1 (tree type, tree op0)
 {
-  tree type = TREE_TYPE (TREE_TYPE (t));
-  tree sub = t;
+  tree sub = op0;
   tree subtype;
 
   STRIP_NOPS (sub);
@@ -11309,12 +11636,18 @@ fold_indirect_ref_1 (tree t)
     {
       tree op = TREE_OPERAND (sub, 0);
       tree optype = TREE_TYPE (op);
-      /* *&p => p */
-      if (lang_hooks.types_compatible_p (type, optype))
-       return op;
+      /* *&p => p;  make sure to handle *&"str"[cst] here.  */
+      if (type == optype)
+       {
+         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
-              && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+              && type == TREE_TYPE (optype))
        {
          tree type_domain = TYPE_DOMAIN (optype);
          tree min_val = size_zero_node;
@@ -11326,7 +11659,7 @@ fold_indirect_ref_1 (tree t)
 
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
   if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
-      && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+      && type == TREE_TYPE (TREE_TYPE (subtype)))
     {
       tree type_domain;
       tree min_val = size_zero_node;
@@ -11346,12 +11679,13 @@ fold_indirect_ref_1 (tree t)
 tree
 build_fold_indirect_ref (tree t)
 {
-  tree sub = fold_indirect_ref_1 (t);
+  tree type = TREE_TYPE (TREE_TYPE (t));
+  tree sub = fold_indirect_ref_1 (type, t);
 
   if (sub)
     return sub;
   else
-    return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
+    return build1 (INDIRECT_REF, type, t);
 }
 
 /* Given an INDIRECT_REF T, return either T or a simplified version.  */
@@ -11359,7 +11693,7 @@ build_fold_indirect_ref (tree t)
 tree
 fold_indirect_ref (tree t)
 {
-  tree sub = fold_indirect_ref_1 (TREE_OPERAND (t, 0));
+  tree sub = fold_indirect_ref_1 (TREE_TYPE (t), TREE_OPERAND (t, 0));
 
   if (sub)
     return sub;
@@ -11525,9 +11859,7 @@ split_address_to_core_and_offset (tree exp,
       core = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, pbitpos,
                                  poffset, &mode, &unsignedp, &volatilep,
                                  false);
-
-      if (TREE_CODE (core) == INDIRECT_REF)
-       core = TREE_OPERAND (core, 0);
+      core = build_fold_addr_expr (core);
     }
   else
     {
@@ -11564,10 +11896,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)
     {