OSDN Git Service

2012-01-04 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index cdae661..40a0986 100644 (file)
@@ -1,6 +1,6 @@
 /* Fold a constant sub-tree into a single node for C-compiler
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -27,8 +27,7 @@ along with GCC; see the file COPYING3.  If not see
   @@ This would also make life easier when this technology is used
   @@ for cross-compilers.  */
 
-/* The entry points in this file are fold, size_int_wide, size_binop
-   and force_fit_type_double.
+/* The entry points in this file are fold, size_int_wide and size_binop.
 
    fold takes a tree as argument and returns a simplified tree.
 
@@ -39,10 +38,6 @@ along with GCC; see the file COPYING3.  If not see
    size_int takes an integer value, and creates a tree constant
    with type from `sizetype'.
 
-   force_fit_type_double takes a constant, an overflowable flag and a
-   prior overflow indicator.  It forces the value to fit the type and
-   sets TREE_OVERFLOW.
-
    Note: Since the folders get called on non-gimple code as well as
    gimple code, we need to handle GIMPLE tuples as well as their
    corresponding tree equivalents.  */
@@ -53,19 +48,19 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "flags.h"
 #include "tree.h"
-#include "real.h"
-#include "fixed-value.h"
+#include "realmpfr.h"
 #include "rtl.h"
 #include "expr.h"
 #include "tm_p.h"
 #include "target.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "intl.h"
 #include "ggc.h"
 #include "hashtab.h"
 #include "langhooks.h"
 #include "md5.h"
 #include "gimple.h"
+#include "tree-flow.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
@@ -98,7 +93,7 @@ static bool negate_expr_p (tree);
 static tree negate_expr (tree);
 static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
 static tree associate_trees (location_t, tree, tree, enum tree_code, tree);
-static tree const_binop (enum tree_code, tree, tree, int);
+static tree const_binop (enum tree_code, tree, tree);
 static enum comparison_code comparison_to_compcode (enum tree_code);
 static enum tree_code compcode_to_comparison (enum comparison_code);
 static int operand_equal_for_comparison_p (tree, tree, tree);
@@ -117,16 +112,13 @@ static tree decode_field_reference (location_t, tree, HOST_WIDE_INT *,
 static int all_ones_mask_p (const_tree, int);
 static tree sign_bit_p (tree, const_tree);
 static int simple_operand_p (const_tree);
+static bool simple_operand_p_2 (tree);
 static tree range_binop (enum tree_code, tree, tree, int, tree, int);
 static tree range_predecessor (tree);
 static tree range_successor (tree);
-extern tree make_range (tree, int *, tree *, tree *, bool *);
-extern bool merge_ranges (int *, tree *, tree *, int, tree, tree, int,
-                         tree, tree);
 static tree fold_range_test (location_t, enum tree_code, tree, tree, tree);
 static tree fold_cond_expr_with_comparison (location_t, tree, tree, tree, tree);
 static tree unextend (tree, int, int, tree);
-static tree fold_truthop (location_t, enum tree_code, tree, tree, tree);
 static tree optimize_minmax_comparison (location_t, enum tree_code,
                                        tree, tree, tree);
 static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *);
@@ -142,10 +134,38 @@ static tree fold_inf_compare (location_t, enum tree_code, tree, tree, tree);
 static tree fold_div_compare (location_t, enum tree_code, tree, tree, tree);
 static bool reorder_operands_p (const_tree, const_tree);
 static tree fold_negate_const (tree, tree);
-static tree fold_not_const (tree, tree);
+static tree fold_not_const (const_tree, tree);
 static tree fold_relational_const (enum tree_code, tree, tree, tree);
 static tree fold_convert_const (enum tree_code, tree, tree);
 
+/* Return EXPR_LOCATION of T if it is not UNKNOWN_LOCATION.
+   Otherwise, return LOC.  */
+
+static location_t
+expr_location_or (tree t, location_t loc)
+{
+  location_t tloc = EXPR_LOCATION (t);
+  return tloc != UNKNOWN_LOCATION ? tloc : loc;
+}
+
+/* Similar to protected_set_expr_location, but never modify x in place,
+   if location can and needs to be set, unshare it.  */
+
+static inline tree
+protected_set_expr_location_unshare (tree x, location_t loc)
+{
+  if (CAN_HAVE_LOCATION_P (x)
+      && EXPR_LOCATION (x) != loc
+      && !(TREE_CODE (x) == SAVE_EXPR
+          || TREE_CODE (x) == TARGET_EXPR
+          || TREE_CODE (x) == BIND_EXPR))
+    {
+      x = copy_node (x);
+      SET_EXPR_LOCATION (x, loc);
+    }
+  return x;
+}
+
 
 /* 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,
@@ -731,10 +751,7 @@ negate_expr (tree t)
 
   tem = fold_negate_expr (loc, t);
   if (!tem)
-    {
-      tem = build1 (NEGATE_EXPR, TREE_TYPE (t), t);
-      SET_EXPR_LOCATION (tem, loc);
-    }
+    tem = build1_loc (loc, NEGATE_EXPR, TREE_TYPE (t), t);
   return fold_convert_loc (loc, type, tem);
 }
 \f
@@ -845,8 +862,6 @@ split_tree (tree in, enum tree_code code, tree *conp, tree *litp,
 static tree
 associate_trees (location_t loc, tree t1, tree t2, enum tree_code code, tree type)
 {
-  tree tem;
-
   if (t1 == 0)
     return t2;
   else if (t2 == 0)
@@ -861,11 +876,15 @@ associate_trees (location_t loc, tree t1, tree t2, enum tree_code code, tree typ
       if (code == PLUS_EXPR)
        {
          if (TREE_CODE (t1) == NEGATE_EXPR)
-           tem = build2 (MINUS_EXPR, type, fold_convert_loc (loc, type, t2),
-                         fold_convert_loc (loc, type, TREE_OPERAND (t1, 0)));
+           return build2_loc (loc, MINUS_EXPR, type,
+                              fold_convert_loc (loc, type, t2),
+                              fold_convert_loc (loc, type,
+                                                TREE_OPERAND (t1, 0)));
          else if (TREE_CODE (t2) == NEGATE_EXPR)
-           tem = build2 (MINUS_EXPR, type, fold_convert_loc (loc, type, t1),
-                         fold_convert_loc (loc, type, TREE_OPERAND (t2, 0)));
+           return build2_loc (loc, MINUS_EXPR, type,
+                              fold_convert_loc (loc, type, t1),
+                              fold_convert_loc (loc, type,
+                                                TREE_OPERAND (t2, 0)));
          else if (integer_zerop (t2))
            return fold_convert_loc (loc, type, t1);
        }
@@ -875,16 +894,12 @@ associate_trees (location_t loc, tree t1, tree t2, enum tree_code code, tree typ
            return fold_convert_loc (loc, type, t1);
        }
 
-      tem = build2 (code, type, fold_convert_loc (loc, type, t1),
-                   fold_convert_loc (loc, type, t2));
-      goto associate_trees_exit;
+      return build2_loc (loc, code, type, fold_convert_loc (loc, type, t1),
+                        fold_convert_loc (loc, type, t2));
     }
 
   return fold_build2_loc (loc, code, type, fold_convert_loc (loc, type, t1),
-                     fold_convert_loc (loc, type, t2));
- associate_trees_exit:
-  protected_set_expr_location (tem, loc);
-  return tem;
+                         fold_convert_loc (loc, type, t2));
 }
 \f
 /* Check whether TYPE1 and TYPE2 are equivalent integer types, suitable
@@ -918,174 +933,154 @@ int_binop_types_match_p (enum tree_code code, const_tree type1, const_tree type2
 
 /* Combine two integer constants ARG1 and ARG2 under operation CODE
    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.  */
+   to evaluate CODE at compile-time.  */
 
 tree
-int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2, int notrunc)
-{
-  unsigned HOST_WIDE_INT int1l, int2l;
-  HOST_WIDE_INT int1h, int2h;
-  unsigned HOST_WIDE_INT low;
-  HOST_WIDE_INT hi;
-  unsigned HOST_WIDE_INT garbagel;
-  HOST_WIDE_INT garbageh;
+int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2)
+{
+  double_int op1, op2, res, tmp;
   tree t;
   tree type = TREE_TYPE (arg1);
-  int uns = TYPE_UNSIGNED (type);
-  int is_sizetype
+  bool uns = TYPE_UNSIGNED (type);
+  bool is_sizetype
     = (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type));
-  int overflow = 0;
+  bool overflow = false;
 
-  int1l = TREE_INT_CST_LOW (arg1);
-  int1h = TREE_INT_CST_HIGH (arg1);
-  int2l = TREE_INT_CST_LOW (arg2);
-  int2h = TREE_INT_CST_HIGH (arg2);
+  op1 = tree_to_double_int (arg1);
+  op2 = tree_to_double_int (arg2);
 
   switch (code)
     {
     case BIT_IOR_EXPR:
-      low = int1l | int2l, hi = int1h | int2h;
+      res = double_int_ior (op1, op2);
       break;
 
     case BIT_XOR_EXPR:
-      low = int1l ^ int2l, hi = int1h ^ int2h;
+      res = double_int_xor (op1, op2);
       break;
 
     case BIT_AND_EXPR:
-      low = int1l & int2l, hi = int1h & int2h;
+      res = double_int_and (op1, op2);
       break;
 
     case RSHIFT_EXPR:
-      int2l = -int2l;
+      res = double_int_rshift (op1, double_int_to_shwi (op2),
+                              TYPE_PRECISION (type), !uns);
+      break;
+
     case LSHIFT_EXPR:
       /* It's unclear from the C standard whether shifts can overflow.
         The following code ignores overflow; perhaps a C standard
         interpretation ruling is needed.  */
-      lshift_double (int1l, int1h, int2l, TYPE_PRECISION (type),
-                    &low, &hi, !uns);
+      res = double_int_lshift (op1, double_int_to_shwi (op2),
+                              TYPE_PRECISION (type), !uns);
       break;
 
     case RROTATE_EXPR:
-      int2l = - int2l;
+      res = double_int_rrotate (op1, double_int_to_shwi (op2),
+                               TYPE_PRECISION (type));
+      break;
+
     case LROTATE_EXPR:
-      lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (type),
-                     &low, &hi);
+      res = double_int_lrotate (op1, double_int_to_shwi (op2),
+                               TYPE_PRECISION (type));
       break;
 
     case PLUS_EXPR:
-      overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi);
+      overflow = add_double (op1.low, op1.high, op2.low, op2.high,
+                            &res.low, &res.high);
       break;
 
     case MINUS_EXPR:
-      neg_double (int2l, int2h, &low, &hi);
-      add_double (int1l, int1h, low, hi, &low, &hi);
-      overflow = OVERFLOW_SUM_SIGN (hi, int2h, int1h);
+      neg_double (op2.low, op2.high, &res.low, &res.high);
+      add_double (op1.low, op1.high, res.low, res.high,
+                 &res.low, &res.high);
+      overflow = OVERFLOW_SUM_SIGN (res.high, op2.high, op1.high);
       break;
 
     case MULT_EXPR:
-      overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
+      overflow = mul_double (op1.low, op1.high, op2.low, op2.high,
+                            &res.low, &res.high);
       break;
 
     case TRUNC_DIV_EXPR:
     case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR:
     case EXACT_DIV_EXPR:
       /* This is a shortcut for a common special case.  */
-      if (int2h == 0 && (HOST_WIDE_INT) int2l > 0
+      if (op2.high == 0 && (HOST_WIDE_INT) op2.low > 0
          && !TREE_OVERFLOW (arg1)
          && !TREE_OVERFLOW (arg2)
-         && int1h == 0 && (HOST_WIDE_INT) int1l >= 0)
+         && op1.high == 0 && (HOST_WIDE_INT) op1.low >= 0)
        {
          if (code == CEIL_DIV_EXPR)
-           int1l += int2l - 1;
+           op1.low += op2.low - 1;
 
-         low = int1l / int2l, hi = 0;
+         res.low = op1.low / op2.low, res.high = 0;
          break;
        }
 
       /* ... fall through ...  */
 
     case ROUND_DIV_EXPR:
-      if (int2h == 0 && int2l == 0)
+      if (double_int_zero_p (op2))
        return NULL_TREE;
-      if (int2h == 0 && int2l == 1)
+      if (double_int_one_p (op2))
        {
-         low = int1l, hi = int1h;
+         res = op1;
          break;
        }
-      if (int1l == int2l && int1h == int2h
-         && ! (int1l == 0 && int1h == 0))
+      if (double_int_equal_p (op1, op2)
+         && ! double_int_zero_p (op1))
        {
-         low = 1, hi = 0;
+         res = double_int_one;
          break;
        }
-      overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
-                                      &low, &hi, &garbagel, &garbageh);
+      overflow = div_and_round_double (code, uns,
+                                      op1.low, op1.high, op2.low, op2.high,
+                                      &res.low, &res.high,
+                                      &tmp.low, &tmp.high);
       break;
 
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
       /* This is a shortcut for a common special case.  */
-      if (int2h == 0 && (HOST_WIDE_INT) int2l > 0
+      if (op2.high == 0 && (HOST_WIDE_INT) op2.low > 0
          && !TREE_OVERFLOW (arg1)
          && !TREE_OVERFLOW (arg2)
-         && int1h == 0 && (HOST_WIDE_INT) int1l >= 0)
+         && op1.high == 0 && (HOST_WIDE_INT) op1.low >= 0)
        {
          if (code == CEIL_MOD_EXPR)
-           int1l += int2l - 1;
-         low = int1l % int2l, hi = 0;
+           op1.low += op2.low - 1;
+         res.low = op1.low % op2.low, res.high = 0;
          break;
        }
 
       /* ... fall through ...  */
 
     case ROUND_MOD_EXPR:
-      if (int2h == 0 && int2l == 0)
+      if (double_int_zero_p (op2))
        return NULL_TREE;
       overflow = div_and_round_double (code, uns,
-                                      int1l, int1h, int2l, int2h,
-                                      &garbagel, &garbageh, &low, &hi);
+                                      op1.low, op1.high, op2.low, op2.high,
+                                      &tmp.low, &tmp.high,
+                                      &res.low, &res.high);
       break;
 
     case MIN_EXPR:
-    case MAX_EXPR:
-      if (uns)
-       low = (((unsigned HOST_WIDE_INT) int1h
-               < (unsigned HOST_WIDE_INT) int2h)
-              || (((unsigned HOST_WIDE_INT) int1h
-                   == (unsigned HOST_WIDE_INT) int2h)
-                  && int1l < int2l));
-      else
-       low = (int1h < int2h
-              || (int1h == int2h && int1l < int2l));
+      res = double_int_min (op1, op2, uns);
+      break;
 
-      if (low == (code == MIN_EXPR))
-       low = int1l, hi = int1h;
-      else
-       low = int2l, hi = int2h;
+    case MAX_EXPR:
+      res = double_int_max (op1, op2, uns);
       break;
 
     default:
       return NULL_TREE;
     }
 
-  if (notrunc)
-    {
-      t = build_int_cst_wide (TREE_TYPE (arg1), low, hi);
-
-      /* Propagate overflow flags ourselves.  */
-      if (((!uns || is_sizetype) && overflow)
-         | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2))
-       {
-         t = copy_node (t);
-         TREE_OVERFLOW (t) = 1;
-       }
-    }
-  else
-    t = force_fit_type_double (TREE_TYPE (arg1), low, hi, 1,
-                              ((!uns || is_sizetype) && overflow)
-                              | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2));
+  t = force_fit_type_double (TREE_TYPE (arg1), res, 1,
+                            ((!uns || is_sizetype) && overflow)
+                            | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2));
 
   return t;
 }
@@ -1093,12 +1088,10 @@ int_const_binop (enum tree_code code, const_tree arg1, const_tree arg2, int notr
 /* Combine two constants ARG1 and ARG2 under operation CODE to produce a new
    constant.  We assume ARG1 and ARG2 have the same data type, or at least
    are the same kind of constant and the same machine mode.  Return zero if
-   combining the constants is not allowed in the current operating mode.
-
-   If NOTRUNC is nonzero, do not truncate the result to fit the data type.  */
+   combining the constants is not allowed in the current operating mode.  */
 
 static tree
-const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
+const_binop (enum tree_code code, tree arg1, tree arg2)
 {
   /* Sanity check for the recursive cases.  */
   if (!arg1 || !arg2)
@@ -1108,7 +1101,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
   STRIP_NOPS (arg2);
 
   if (TREE_CODE (arg1) == INTEGER_CST)
-    return int_const_binop (code, arg1, arg2, notrunc);
+    return int_const_binop (code, arg1, arg2);
 
   if (TREE_CODE (arg1) == REAL_CST)
     {
@@ -1242,8 +1235,8 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
        {
        case PLUS_EXPR:
        case MINUS_EXPR:
-         real = const_binop (code, r1, r2, notrunc);
-         imag = const_binop (code, i1, i2, notrunc);
+         real = const_binop (code, r1, r2);
+         imag = const_binop (code, i1, i2);
          break;
 
        case MULT_EXPR:
@@ -1253,13 +1246,11 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
                                mpc_mul);
 
          real = const_binop (MINUS_EXPR,
-                             const_binop (MULT_EXPR, r1, r2, notrunc),
-                             const_binop (MULT_EXPR, i1, i2, notrunc),
-                             notrunc);
+                             const_binop (MULT_EXPR, r1, r2),
+                             const_binop (MULT_EXPR, i1, i2));
          imag = const_binop (PLUS_EXPR,
-                             const_binop (MULT_EXPR, r1, i2, notrunc),
-                             const_binop (MULT_EXPR, i1, r2, notrunc),
-                             notrunc);
+                             const_binop (MULT_EXPR, r1, i2),
+                             const_binop (MULT_EXPR, i1, r2));
          break;
 
        case RDIV_EXPR:
@@ -1283,22 +1274,19 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
            */
            tree magsquared
              = const_binop (PLUS_EXPR,
-                            const_binop (MULT_EXPR, r2, r2, notrunc),
-                            const_binop (MULT_EXPR, i2, i2, notrunc),
-                            notrunc);
+                            const_binop (MULT_EXPR, r2, r2),
+                            const_binop (MULT_EXPR, i2, i2));
            tree t1
              = const_binop (PLUS_EXPR,
-                            const_binop (MULT_EXPR, r1, r2, notrunc),
-                            const_binop (MULT_EXPR, i1, i2, notrunc),
-                            notrunc);
+                            const_binop (MULT_EXPR, r1, r2),
+                            const_binop (MULT_EXPR, i1, i2));
            tree t2
              = const_binop (MINUS_EXPR,
-                            const_binop (MULT_EXPR, i1, r2, notrunc),
-                            const_binop (MULT_EXPR, r1, i2, notrunc),
-                            notrunc);
+                            const_binop (MULT_EXPR, i1, r2),
+                            const_binop (MULT_EXPR, r1, i2));
 
-           real = const_binop (code, t1, magsquared, notrunc);
-           imag = const_binop (code, t2, magsquared, notrunc);
+           real = const_binop (code, t1, magsquared);
+           imag = const_binop (code, t2, magsquared);
          }
          else
          {
@@ -1320,18 +1308,16 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
                   ti = (ai * ratio) - ar;
                   tr = tr / div;
                   ti = ti / div;  */
-               tree ratio = const_binop (code, r2, i2, notrunc);
+               tree ratio = const_binop (code, r2, i2);
                tree div = const_binop (PLUS_EXPR, i2,
-                                       const_binop (MULT_EXPR, r2, ratio,
-                                                    notrunc),
-                                       notrunc);
-               real = const_binop (MULT_EXPR, r1, ratio, notrunc);
-               real = const_binop (PLUS_EXPR, real, i1, notrunc);
-               real = const_binop (code, real, div, notrunc);
-
-               imag = const_binop (MULT_EXPR, i1, ratio, notrunc);
-               imag = const_binop (MINUS_EXPR, imag, r1, notrunc);
-               imag = const_binop (code, imag, div, notrunc);
+                                       const_binop (MULT_EXPR, r2, ratio));
+               real = const_binop (MULT_EXPR, r1, ratio);
+               real = const_binop (PLUS_EXPR, real, i1);
+               real = const_binop (code, real, div);
+
+               imag = const_binop (MULT_EXPR, i1, ratio);
+               imag = const_binop (MINUS_EXPR, imag, r1);
+               imag = const_binop (code, imag, div);
              }
            else
              {
@@ -1342,19 +1328,17 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
                   ti = b - (a * ratio);
                   tr = tr / div;
                   ti = ti / div;  */
-               tree ratio = const_binop (code, i2, r2, notrunc);
+               tree ratio = const_binop (code, i2, r2);
                tree div = const_binop (PLUS_EXPR, r2,
-                                        const_binop (MULT_EXPR, i2, ratio,
-                                                    notrunc),
-                                       notrunc);
+                                        const_binop (MULT_EXPR, i2, ratio));
 
-               real = const_binop (MULT_EXPR, i1, ratio, notrunc);
-               real = const_binop (PLUS_EXPR, real, r1, notrunc);
-               real = const_binop (code, real, div, notrunc);
+               real = const_binop (MULT_EXPR, i1, ratio);
+               real = const_binop (PLUS_EXPR, real, r1);
+               real = const_binop (code, real, div);
 
-               imag = const_binop (MULT_EXPR, r1, ratio, notrunc);
-               imag = const_binop (MINUS_EXPR, i1, imag, notrunc);
-               imag = const_binop (code, imag, div, notrunc);
+               imag = const_binop (MULT_EXPR, r1, ratio);
+               imag = const_binop (MINUS_EXPR, i1, imag);
+               imag = const_binop (code, imag, div);
              }
          }
          break;
@@ -1400,7 +1384,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
               elements2 = TREE_CHAIN (elements2);
             }
 
-          elem = const_binop (code, elem1, elem2, notrunc);
+          elem = const_binop (code, elem1, elem2);
 
           /* It is possible that const_binop cannot handle the given
             code and return NULL_TREE */
@@ -1462,7 +1446,7 @@ size_binop_loc (location_t loc, enum tree_code code, tree arg0, tree arg1)
        }
 
       /* Handle general case of two integer constants.  */
-      return int_const_binop (code, arg0, arg1, 0);
+      return int_const_binop (code, arg0, arg1);
     }
 
   return fold_build2_loc (loc, code, type, arg0, arg1);
@@ -1527,8 +1511,7 @@ fold_convert_const_int_from_int (tree type, const_tree arg1)
 
   /* Given an integer constant, make new constant with new type,
      appropriately sign-extended or truncated.  */
-  t = force_fit_type_double (type, TREE_INT_CST_LOW (arg1),
-                            TREE_INT_CST_HIGH (arg1),
+  t = force_fit_type_double (type, tree_to_double_int (arg1),
                             !POINTER_TYPE_P (TREE_TYPE (arg1)),
                             (TREE_INT_CST_HIGH (arg1) < 0
                              && (TYPE_UNSIGNED (type)
@@ -1608,8 +1591,7 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg
   if (! overflow)
     real_to_integer2 ((HOST_WIDE_INT *) &val.low, &val.high, &r);
 
-  t = force_fit_type_double (type, val.low, val.high, -1,
-                            overflow | TREE_OVERFLOW (arg1));
+  t = force_fit_type_double (type, val, -1, overflow | TREE_OVERFLOW (arg1));
   return t;
 }
 
@@ -1652,7 +1634,7 @@ fold_convert_const_int_from_fixed (tree type, const_tree arg1)
 
   /* Given a fixed-point constant, make new constant with new type,
      appropriately sign-extended or truncated.  */
-  t = force_fit_type_double (type, temp.low, temp.high, -1,
+  t = force_fit_type_double (type, temp, -1,
                             (double_int_negative_p (temp)
                              && (TYPE_UNSIGNED (type)
                                  < TYPE_UNSIGNED (TREE_TYPE (arg1))))
@@ -1818,16 +1800,10 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
 static tree
 build_zero_vector (tree type)
 {
-  tree elem, list;
-  int i, units;
-
-  elem = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node);
-  units = TYPE_VECTOR_SUBPARTS (type);
+  tree t;
 
-  list = NULL_TREE;
-  for (i = 0; i < units; i++)
-    list = tree_cons (NULL_TREE, elem, list);
-  return build_vector (type, list);
+  t = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node);
+  return build_vector_from_val (type, t);
 }
 
 /* Returns true, if ARG is convertible to TYPE using a NOP_EXPR.  */
@@ -1888,9 +1864,6 @@ fold_convert_loc (location_t loc, tree type, tree arg)
       || TREE_CODE (orig) == ERROR_MARK)
     return error_mark_node;
 
-  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig))
-    return fold_build1_loc (loc, NOP_EXPR, type, arg);
-
   switch (TREE_CODE (type))
     {
     case POINTER_TYPE:
@@ -2035,15 +2008,15 @@ fold_convert_loc (location_t loc, tree type, tree arg)
 
     case VOID_TYPE:
       tem = fold_ignored_result (arg);
-      if (TREE_CODE (tem) == MODIFY_EXPR)
-       goto fold_convert_exit;
       return fold_build1_loc (loc, NOP_EXPR, type, tem);
 
     default:
+      if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig))
+       return fold_build1_loc (loc, NOP_EXPR, type, arg);
       gcc_unreachable ();
     }
  fold_convert_exit:
-  protected_set_expr_location (tem, loc);
+  protected_set_expr_location_unshare (tem, loc);
   return tem;
 }
 \f
@@ -2064,9 +2037,8 @@ maybe_lvalue_p (const_tree x)
   case SSA_NAME:
 
   case COMPONENT_REF:
+  case MEM_REF:
   case INDIRECT_REF:
-  case ALIGN_INDIRECT_REF:
-  case MISALIGNED_INDIRECT_REF:
   case ARRAY_REF:
   case ARRAY_RANGE_REF:
   case BIT_FIELD_REF:
@@ -2108,9 +2080,7 @@ non_lvalue_loc (location_t loc, tree x)
 
   if (! maybe_lvalue_p (x))
     return x;
-  x = build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
-  SET_EXPR_LOCATION (x, loc);
-  return x;
+  return build1_loc (loc, NON_LVALUE_EXPR, TREE_TYPE (x), x);
 }
 
 /* Nonzero means lvalues are limited to those valid in pedantic ANSI C.
@@ -2126,19 +2096,18 @@ pedantic_non_lvalue_loc (location_t loc, tree x)
 {
   if (pedantic_lvalues)
     return non_lvalue_loc (loc, x);
-  protected_set_expr_location (x, loc);
-  return x;
+
+  return protected_set_expr_location_unshare (x, loc);
 }
 \f
-/* Given a tree comparison code, return the code that is the logical inverse
-   of the given code.  It is not safe to do this for floating-point
-   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.  */
+/* Given a tree comparison code, return the code that is the logical inverse.
+   It is generally not safe to do this for floating-point comparisons, except
+   for EQ_EXPR and NE_EXPR, so we return ERROR_MARK in this case.  */
 
 enum tree_code
 invert_tree_comparison (enum tree_code code, bool honor_nans)
 {
-  if (honor_nans && flag_trapping_math)
+  if (honor_nans && flag_trapping_math && code != EQ_EXPR && code != NE_EXPR)
     return ERROR_MARK;
 
   switch (code)
@@ -2484,9 +2453,12 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
      equal if they have no side effects.  If we have two identical
      expressions with side effects that should be treated the same due
      to the only side effects being identical SAVE_EXPR's, that will
-     be detected in the recursive calls below.  */
+     be detected in the recursive calls below.
+     If we are taking an invariant address of two identical objects
+     they are necessarily equal as well.  */
   if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST)
       && (TREE_CODE (arg0) == SAVE_EXPR
+         || (flags & OEP_CONSTANT_ADDRESS_OF)
          || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
     return 1;
 
@@ -2549,7 +2521,8 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 
       case ADDR_EXPR:
        return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
-                               0);
+                               TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)
+                               ? OEP_CONSTANT_ADDRESS_OF : 0);
       default:
        break;
       }
@@ -2609,12 +2582,24 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
       switch (TREE_CODE (arg0))
        {
        case INDIRECT_REF:
-       case ALIGN_INDIRECT_REF:
-       case MISALIGNED_INDIRECT_REF:
        case REALPART_EXPR:
        case IMAGPART_EXPR:
          return OP_SAME (0);
 
+       case MEM_REF:
+         /* Require equal access sizes, and similar pointer types.
+            We can have incomplete types for array references of
+            variable-sized arrays from the Fortran frontent
+            though.  */
+         return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1))
+                  || (TYPE_SIZE (TREE_TYPE (arg0))
+                      && TYPE_SIZE (TREE_TYPE (arg1))
+                      && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
+                                          TYPE_SIZE (TREE_TYPE (arg1)), flags)))
+                 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1)))
+                     == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 1))))
+                 && OP_SAME (0) && OP_SAME (1));
+
        case ARRAY_REF:
        case ARRAY_RANGE_REF:
          /* Operands 2 and 3 may be null.
@@ -2652,6 +2637,14 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
        case TRUTH_ORIF_EXPR:
          return OP_SAME (0) && OP_SAME (1);
 
+       case FMA_EXPR:
+       case WIDEN_MULT_PLUS_EXPR:
+       case WIDEN_MULT_MINUS_EXPR:
+         if (!OP_SAME (2))
+           return 0;
+         /* The multiplcation operands are commutative.  */
+         /* FALLTHRU */
+
        case TRUTH_AND_EXPR:
        case TRUTH_OR_EXPR:
        case TRUTH_XOR_EXPR:
@@ -2665,6 +2658,8 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
                                      TREE_OPERAND (arg1, 0), flags));
 
        case COND_EXPR:
+       case VEC_COND_EXPR:
+       case DOT_PROD_EXPR:
          return OP_SAME (0) && OP_SAME (1) && OP_SAME (2);
 
        default:
@@ -2979,22 +2974,14 @@ omit_one_operand_loc (location_t loc, tree type, tree result, tree omitted)
   /* If the resulting operand is an empty statement, just return the omitted
      statement casted to void. */
   if (IS_EMPTY_STMT (t) && TREE_SIDE_EFFECTS (omitted))
-    {
-      t = build1 (NOP_EXPR, void_type_node, fold_ignored_result (omitted));
-      goto omit_one_operand_exit;
-    }
+    return build1_loc (loc, NOP_EXPR, void_type_node,
+                      fold_ignored_result (omitted));
 
   if (TREE_SIDE_EFFECTS (omitted))
-    {
-      t = build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t);
-      goto omit_one_operand_exit;
-    }
+    return build2_loc (loc, COMPOUND_EXPR, type,
+                      fold_ignored_result (omitted), t);
 
   return non_lvalue_loc (loc, t);
-
- omit_one_operand_exit:
-  protected_set_expr_location (t, loc);
-  return t;
 }
 
 /* Similar, but call pedantic_non_lvalue instead of non_lvalue.  */
@@ -3008,22 +2995,14 @@ pedantic_omit_one_operand_loc (location_t loc, tree type, tree result,
   /* If the resulting operand is an empty statement, just return the omitted
      statement casted to void. */
   if (IS_EMPTY_STMT (t) && TREE_SIDE_EFFECTS (omitted))
-    {
-      t = build1 (NOP_EXPR, void_type_node, fold_ignored_result (omitted));
-      goto pedantic_omit_one_operand_exit;
-    }
+    return build1_loc (loc, NOP_EXPR, void_type_node,
+                      fold_ignored_result (omitted));
 
   if (TREE_SIDE_EFFECTS (omitted))
-    {
-      t = build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t);
-      goto pedantic_omit_one_operand_exit;
-    }
+    return build2_loc (loc, COMPOUND_EXPR, type,
+                      fold_ignored_result (omitted), t);
 
   return pedantic_non_lvalue_loc (loc, t);
-
- pedantic_omit_one_operand_exit:
-  protected_set_expr_location (t, loc);
-  return t;
 }
 
 /* Return a tree for the case when the result of an expression is RESULT
@@ -3037,20 +3016,14 @@ pedantic_omit_one_operand_loc (location_t loc, tree type, tree result,
 
 tree
 omit_two_operands_loc (location_t loc, tree type, tree result,
-                  tree omitted1, tree omitted2)
+                      tree omitted1, tree omitted2)
 {
   tree t = fold_convert_loc (loc, type, result);
 
   if (TREE_SIDE_EFFECTS (omitted2))
-    {
-      t = build2 (COMPOUND_EXPR, type, omitted2, t);
-      SET_EXPR_LOCATION (t, loc);
-    }
+    t = build2_loc (loc, COMPOUND_EXPR, type, omitted2, t);
   if (TREE_SIDE_EFFECTS (omitted1))
-    {
-      t = build2 (COMPOUND_EXPR, type, omitted1, t);
-      SET_EXPR_LOCATION (t, loc);
-    }
+    t = build2_loc (loc, COMPOUND_EXPR, type, omitted1, t);
 
   return TREE_CODE (t) != COMPOUND_EXPR ? non_lvalue_loc (loc, t) : t;
 }
@@ -3066,7 +3039,7 @@ omit_two_operands_loc (location_t loc, tree type, tree result,
 tree
 fold_truth_not_expr (location_t loc, tree arg)
 {
-  tree t, type = TREE_TYPE (arg);
+  tree type = TREE_TYPE (arg);
   enum tree_code code = TREE_CODE (arg);
   location_t loc1, loc2;
 
@@ -3087,9 +3060,8 @@ fold_truth_not_expr (location_t loc, tree arg)
       if (code == ERROR_MARK)
        return NULL_TREE;
 
-      t = build2 (code, type, TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1));
-      SET_EXPR_LOCATION (t, loc);
-      return t;
+      return build2_loc (loc, code, type, TREE_OPERAND (arg, 0),
+                        TREE_OPERAND (arg, 1));
     }
 
   switch (code)
@@ -3098,28 +3070,18 @@ fold_truth_not_expr (location_t loc, tree arg)
       return constant_boolean_node (integer_zerop (arg), type);
 
     case TRUTH_AND_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 0));
-      loc2 = EXPR_LOCATION (TREE_OPERAND (arg, 1));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
-      if (loc2 == UNKNOWN_LOCATION)
-       loc2 = loc;
-      t = build2 (TRUTH_OR_EXPR, type,
-                 invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
-                 invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
-      break;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
+      loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc);
+      return build2_loc (loc, TRUTH_OR_EXPR, type,
+                        invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
+                        invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
 
     case TRUTH_OR_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 0));
-      loc2 = EXPR_LOCATION (TREE_OPERAND (arg, 1));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
-      if (loc2 == UNKNOWN_LOCATION)
-       loc2 = loc;
-      t = build2 (TRUTH_AND_EXPR, type,
-                 invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
-                 invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
-      break;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
+      loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc);
+      return build2_loc (loc, TRUTH_AND_EXPR, type,
+                        invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
+                        invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
 
     case TRUTH_XOR_EXPR:
       /* Here we can invert either operand.  We invert the first operand
@@ -3128,37 +3090,26 @@ fold_truth_not_expr (location_t loc, tree arg)
         negation of the second operand.  */
 
       if (TREE_CODE (TREE_OPERAND (arg, 1)) == TRUTH_NOT_EXPR)
-       t = build2 (TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0),
-                   TREE_OPERAND (TREE_OPERAND (arg, 1), 0));
+       return build2_loc (loc, TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0),
+                          TREE_OPERAND (TREE_OPERAND (arg, 1), 0));
       else
-       t = build2 (TRUTH_XOR_EXPR, type,
-                   invert_truthvalue_loc (loc, TREE_OPERAND (arg, 0)),
-                   TREE_OPERAND (arg, 1));
-      break;
+       return build2_loc (loc, TRUTH_XOR_EXPR, type,
+                          invert_truthvalue_loc (loc, TREE_OPERAND (arg, 0)),
+                          TREE_OPERAND (arg, 1));
 
     case TRUTH_ANDIF_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 0));
-      loc2 = EXPR_LOCATION (TREE_OPERAND (arg, 1));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
-      if (loc2 == UNKNOWN_LOCATION)
-       loc2 = loc;
-      t = build2 (TRUTH_ORIF_EXPR, type,
-                 invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
-                 invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
-      break;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
+      loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc);
+      return build2_loc (loc, TRUTH_ORIF_EXPR, type,
+                        invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
+                        invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
 
     case TRUTH_ORIF_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 0));
-      loc2 = EXPR_LOCATION (TREE_OPERAND (arg, 1));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
-      if (loc2 == UNKNOWN_LOCATION)
-       loc2 = loc;
-      t = build2 (TRUTH_ANDIF_EXPR, type,
-                 invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
-                 invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
-      break;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
+      loc2 = expr_location_or (TREE_OPERAND (arg, 1), loc);
+      return build2_loc (loc, TRUTH_ANDIF_EXPR, type,
+                        invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)),
+                        invert_truthvalue_loc (loc2, TREE_OPERAND (arg, 1)));
 
     case TRUTH_NOT_EXPR:
       return TREE_OPERAND (arg, 0);
@@ -3168,83 +3119,56 @@ fold_truth_not_expr (location_t loc, tree arg)
        tree arg1 = TREE_OPERAND (arg, 1);
        tree arg2 = TREE_OPERAND (arg, 2);
 
-       loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 1));
-       loc2 = EXPR_LOCATION (TREE_OPERAND (arg, 2));
-       if (loc1 == UNKNOWN_LOCATION)
-         loc1 = loc;
-       if (loc2 == UNKNOWN_LOCATION)
-         loc2 = loc;
+       loc1 = expr_location_or (TREE_OPERAND (arg, 1), loc);
+       loc2 = expr_location_or (TREE_OPERAND (arg, 2), loc);
 
        /* A COND_EXPR may have a throw as one operand, which
           then has void type.  Just leave void operands
           as they are.  */
-       t = build3 (COND_EXPR, type, TREE_OPERAND (arg, 0),
-                   VOID_TYPE_P (TREE_TYPE (arg1))
-                   ? arg1 : invert_truthvalue_loc (loc1, arg1),
-                   VOID_TYPE_P (TREE_TYPE (arg2))
-                   ? arg2 : invert_truthvalue_loc (loc2, arg2));
-       break;
+       return build3_loc (loc, COND_EXPR, type, TREE_OPERAND (arg, 0),
+                          VOID_TYPE_P (TREE_TYPE (arg1))
+                          ? arg1 : invert_truthvalue_loc (loc1, arg1),
+                          VOID_TYPE_P (TREE_TYPE (arg2))
+                          ? arg2 : invert_truthvalue_loc (loc2, arg2));
       }
 
     case COMPOUND_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 1));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
-      t = build2 (COMPOUND_EXPR, type,
-                 TREE_OPERAND (arg, 0),
-                 invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 1)));
-      break;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 1), loc);
+      return build2_loc (loc, COMPOUND_EXPR, type,
+                        TREE_OPERAND (arg, 0),
+                        invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 1)));
 
     case NON_LVALUE_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 0));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
       return invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0));
 
     CASE_CONVERT:
       if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
-       {
-         t = build1 (TRUTH_NOT_EXPR, type, arg);
-         break;
-       }
+       return build1_loc (loc, TRUTH_NOT_EXPR, type, arg);
 
       /* ... fall through ...  */
 
     case FLOAT_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 0));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
-      t = build1 (TREE_CODE (arg), type,
-                 invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)));
-      break;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
+      return build1_loc (loc, TREE_CODE (arg), type,
+                        invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)));
 
     case BIT_AND_EXPR:
       if (!integer_onep (TREE_OPERAND (arg, 1)))
        return NULL_TREE;
-      t = build2 (EQ_EXPR, type, arg, build_int_cst (type, 0));
-      break;
+      return build2_loc (loc, EQ_EXPR, type, arg, build_int_cst (type, 0));
 
     case SAVE_EXPR:
-      t = build1 (TRUTH_NOT_EXPR, type, arg);
-      break;
+      return build1_loc (loc, TRUTH_NOT_EXPR, type, arg);
 
     case CLEANUP_POINT_EXPR:
-      loc1 = EXPR_LOCATION (TREE_OPERAND (arg, 0));
-      if (loc1 == UNKNOWN_LOCATION)
-       loc1 = loc;
-      t = build1 (CLEANUP_POINT_EXPR, type,
-                 invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)));
-      break;
+      loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
+      return build1_loc (loc, CLEANUP_POINT_EXPR, type,
+                        invert_truthvalue_loc (loc1, TREE_OPERAND (arg, 0)));
 
     default:
-      t = NULL_TREE;
-      break;
+      return NULL_TREE;
     }
-
-  if (t)
-    SET_EXPR_LOCATION (t, loc);
-
-  return t;
 }
 
 /* Return a simplified tree node for the truth-negation of ARG.  This
@@ -3264,10 +3188,7 @@ invert_truthvalue_loc (location_t loc, tree arg)
 
   tem = fold_truth_not_expr (loc, arg);
   if (!tem)
-    {
-      tem = build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg), arg);
-      SET_EXPR_LOCATION (tem, loc);
-    }
+    tem = build1_loc (loc, TRUTH_NOT_EXPR, TREE_TYPE (arg), arg);
 
   return tem;
 }
@@ -3393,9 +3314,8 @@ make_bit_field_ref (location_t loc, tree inner, tree type,
       || TYPE_UNSIGNED (bftype) == !unsignedp)
     bftype = build_nonstandard_integer_type (bitsize, 0);
 
-  result = build3 (BIT_FIELD_REF, bftype, inner,
-                  size_int (bitsize), bitsize_int (bitpos));
-  SET_EXPR_LOCATION (result, loc);
+  result = build3_loc (loc, BIT_FIELD_REF, bftype, inner,
+                      size_int (bitsize), bitsize_int (bitpos));
 
   if (bftype != type)
     result = fold_convert_loc (loc, type, result);
@@ -3464,11 +3384,16 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
 
   /* See if we can find a mode to refer to this field.  We should be able to,
      but fail if we can't.  */
-  nmode = get_best_mode (lbitsize, lbitpos,
-                        const_p ? TYPE_ALIGN (TREE_TYPE (linner))
-                        : MIN (TYPE_ALIGN (TREE_TYPE (linner)),
-                               TYPE_ALIGN (TREE_TYPE (rinner))),
-                        word_mode, lvolatilep || rvolatilep);
+  if (lvolatilep
+      && GET_MODE_BITSIZE (lmode) > 0
+      && flag_strict_volatile_bitfields > 0)
+    nmode = lmode;
+  else
+    nmode = get_best_mode (lbitsize, lbitpos, 0, 0,
+                          const_p ? TYPE_ALIGN (TREE_TYPE (linner))
+                          : MIN (TYPE_ALIGN (TREE_TYPE (linner)),
+                                 TYPE_ALIGN (TREE_TYPE (rinner))),
+                          word_mode, lvolatilep || rvolatilep);
   if (nmode == VOIDmode)
     return 0;
 
@@ -3491,9 +3416,9 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
 
   /* Make the mask to be used against the extracted field.  */
   mask = build_int_cst_type (unsigned_type, -1);
-  mask = const_binop (LSHIFT_EXPR, mask, size_int (nbitsize - lbitsize), 0);
+  mask = const_binop (LSHIFT_EXPR, mask, size_int (nbitsize - lbitsize));
   mask = const_binop (RSHIFT_EXPR, mask,
-                     size_int (nbitsize - lbitsize - lbitpos), 0);
+                     size_int (nbitsize - lbitsize - lbitpos));
 
   if (! const_p)
     /* If not comparing with constant, just rework the comparison
@@ -3526,7 +3451,7 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
       if (! integer_zerop (const_binop (RSHIFT_EXPR,
                                        fold_convert_loc (loc,
                                                          unsigned_type, rhs),
-                                       size_int (lbitsize), 0)))
+                                       size_int (lbitsize))))
        {
          warning (0, "comparison is always %d due to width of bit-field",
                   code == NE_EXPR);
@@ -3537,7 +3462,7 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
     {
       tree tem = const_binop (RSHIFT_EXPR,
                              fold_convert_loc (loc, signed_type, rhs),
-                             size_int (lbitsize - 1), 0);
+                             size_int (lbitsize - 1));
       if (! integer_zerop (tem) && ! integer_all_onesp (tem))
        {
          warning (0, "comparison is always %d due to width of bit-field",
@@ -3566,17 +3491,15 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
   rhs = const_binop (BIT_AND_EXPR,
                     const_binop (LSHIFT_EXPR,
                                  fold_convert_loc (loc, unsigned_type, rhs),
-                                 size_int (lbitpos), 0),
-                    mask, 0);
+                                 size_int (lbitpos)),
+                    mask);
 
-  lhs = build2 (code, compare_type,
-               build2 (BIT_AND_EXPR, unsigned_type, lhs, mask),
-               rhs);
-  SET_EXPR_LOCATION (lhs, loc);
+  lhs = build2_loc (loc, code, compare_type,
+                   build2 (BIT_AND_EXPR, unsigned_type, lhs, mask), rhs);
   return lhs;
 }
 \f
-/* Subroutine for fold_truthop: decode a field reference.
+/* Subroutine for fold_truth_andor_1: decode a field reference.
 
    If EXP is a comparison reference, we return the innermost reference.
 
@@ -3653,8 +3576,8 @@ decode_field_reference (location_t loc, tree exp, HOST_WIDE_INT *pbitsize,
 
   mask = build_int_cst_type (unsigned_type, -1);
 
-  mask = const_binop (LSHIFT_EXPR, mask, size_int (precision - *pbitsize), 0);
-  mask = const_binop (RSHIFT_EXPR, mask, size_int (precision - *pbitsize), 0);
+  mask = const_binop (LSHIFT_EXPR, mask, size_int (precision - *pbitsize));
+  mask = const_binop (RSHIFT_EXPR, mask, size_int (precision - *pbitsize));
 
   /* Merge it with the mask we found in the BIT_AND_EXPR, if any.  */
   if (and_mask != 0)
@@ -3682,9 +3605,8 @@ all_ones_mask_p (const_tree mask, int size)
     tree_int_cst_equal (mask,
                        const_binop (RSHIFT_EXPR,
                                     const_binop (LSHIFT_EXPR, tmask,
-                                                 size_int (precision - size),
-                                                 0),
-                                    size_int (precision - size), 0));
+                                                 size_int (precision - size)),
+                                    size_int (precision - size)));
 }
 
 /* Subroutine for fold: determine if VAL is the INTEGER_CONST that
@@ -3745,7 +3667,7 @@ sign_bit_p (tree exp, const_tree val)
   return NULL_TREE;
 }
 
-/* Subroutine for fold_truthop: determine if an operand is simple enough
+/* Subroutine for fold_truth_andor_1: determine if an operand is simple enough
    to be evaluated unconditionally.  */
 
 static int
@@ -3755,7 +3677,7 @@ simple_operand_p (const_tree exp)
   STRIP_NOPS (exp);
 
   return (CONSTANT_CLASS_P (exp)
-         || TREE_CODE (exp) == SSA_NAME
+         || TREE_CODE (exp) == SSA_NAME
          || (DECL_P (exp)
              && ! TREE_ADDRESSABLE (exp)
              && ! TREE_THIS_VOLATILE (exp)
@@ -3769,6 +3691,36 @@ simple_operand_p (const_tree exp)
                 registers aren't expensive.  */
              && (! TREE_STATIC (exp) || DECL_REGISTER (exp))));
 }
+
+/* Subroutine for fold_truth_andor: determine if an operand is simple enough
+   to be evaluated unconditionally.
+   I addition to simple_operand_p, we assume that comparisons, conversions,
+   and logic-not operations are simple, if their operands are simple, too.  */
+
+static bool
+simple_operand_p_2 (tree exp)
+{
+  enum tree_code code;
+
+  if (TREE_SIDE_EFFECTS (exp)
+      || tree_could_trap_p (exp))
+    return false;
+
+  while (CONVERT_EXPR_P (exp))
+    exp = TREE_OPERAND (exp, 0);
+
+  code = TREE_CODE (exp);
+
+  if (TREE_CODE_CLASS (code) == tcc_comparison)
+    return (simple_operand_p (TREE_OPERAND (exp, 0))
+           && simple_operand_p (TREE_OPERAND (exp, 1)));
+
+  if (code == TRUTH_NOT_EXPR)
+      return simple_operand_p_2 (TREE_OPERAND (exp, 0));
+
+  return simple_operand_p (exp);
+}
+
 \f
 /* The following functions are subroutines to fold_range_test and allow it to
    try to change a logical combination of comparisons into a range test.
@@ -3864,288 +3816,308 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
   return constant_boolean_node (result, type);
 }
 \f
-/* Given EXP, a logical expression, set the range it is testing into
-   variables denoted by PIN_P, PLOW, and PHIGH.  Return the expression
-   actually being tested.  *PLOW and *PHIGH will be made of the same
-   type as the returned expression.  If EXP is not a comparison, we
-   will most likely not be returning a useful value and range.  Set
-   *STRICT_OVERFLOW_P to true if the return value is only valid
-   because signed overflow is undefined; otherwise, do not change
-   *STRICT_OVERFLOW_P.  */
+/* Helper routine for make_range.  Perform one step for it, return
+   new expression if the loop should continue or NULL_TREE if it should
+   stop.  */
 
 tree
-make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
-           bool *strict_overflow_p)
+make_range_step (location_t loc, enum tree_code code, tree arg0, tree arg1,
+                tree exp_type, tree *p_low, tree *p_high, int *p_in_p,
+                bool *strict_overflow_p)
 {
-  enum tree_code code;
-  tree arg0 = NULL_TREE, arg1 = NULL_TREE;
-  tree exp_type = NULL_TREE, arg0_type = NULL_TREE;
-  int in_p, n_in_p;
-  tree low, high, n_low, n_high;
-  location_t loc = EXPR_LOCATION (exp);
-
-  /* Start with simply saying "EXP != 0" and then look at the code of EXP
-     and see if we can refine the range.  Some of the cases below may not
-     happen, but it doesn't seem worth worrying about this.  We "continue"
-     the outer loop when we've changed something; otherwise we "break"
-     the switch, which will "break" the while.  */
-
-  in_p = 0;
-  low = high = build_int_cst (TREE_TYPE (exp), 0);
+  tree arg0_type = TREE_TYPE (arg0);
+  tree n_low, n_high, low = *p_low, high = *p_high;
+  int in_p = *p_in_p, n_in_p;
 
-  while (1)
+  switch (code)
     {
-      code = TREE_CODE (exp);
-      exp_type = TREE_TYPE (exp);
+    case TRUTH_NOT_EXPR:
+      *p_in_p = ! in_p;
+      return arg0;
+
+    case EQ_EXPR: case NE_EXPR:
+    case LT_EXPR: case LE_EXPR: case GE_EXPR: case GT_EXPR:
+      /* We can only do something if the range is testing for zero
+        and if the second operand is an integer constant.  Note that
+        saying something is "in" the range we make is done by
+        complementing IN_P since it will set in the initial case of
+        being not equal to zero; "out" is leaving it alone.  */
+      if (low == NULL_TREE || high == NULL_TREE
+         || ! integer_zerop (low) || ! integer_zerop (high)
+         || TREE_CODE (arg1) != INTEGER_CST)
+       return NULL_TREE;
 
-      if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+      switch (code)
        {
-         if (TREE_OPERAND_LENGTH (exp) > 0)
-           arg0 = TREE_OPERAND (exp, 0);
-         if (TREE_CODE_CLASS (code) == tcc_comparison
-             || TREE_CODE_CLASS (code) == tcc_unary
-             || TREE_CODE_CLASS (code) == tcc_binary)
-           arg0_type = TREE_TYPE (arg0);
-         if (TREE_CODE_CLASS (code) == tcc_binary
-             || TREE_CODE_CLASS (code) == tcc_comparison
-             || (TREE_CODE_CLASS (code) == tcc_expression
-                 && TREE_OPERAND_LENGTH (exp) > 1))
-           arg1 = TREE_OPERAND (exp, 1);
+       case NE_EXPR:  /* - [c, c]  */
+         low = high = arg1;
+         break;
+       case EQ_EXPR:  /* + [c, c]  */
+         in_p = ! in_p, low = high = arg1;
+         break;
+       case GT_EXPR:  /* - [-, c] */
+         low = 0, high = arg1;
+         break;
+       case GE_EXPR:  /* + [c, -] */
+         in_p = ! in_p, low = arg1, high = 0;
+         break;
+       case LT_EXPR:  /* - [c, -] */
+         low = arg1, high = 0;
+         break;
+       case LE_EXPR:  /* + [-, c] */
+         in_p = ! in_p, low = 0, high = arg1;
+         break;
+       default:
+         gcc_unreachable ();
        }
 
-      switch (code)
+      /* If this is an unsigned comparison, we also know that EXP is
+        greater than or equal to zero.  We base the range tests we make
+        on that fact, so we record it here so we can parse existing
+        range tests.  We test arg0_type since often the return type
+        of, e.g. EQ_EXPR, is boolean.  */
+      if (TYPE_UNSIGNED (arg0_type) && (low == 0 || high == 0))
        {
-       case TRUTH_NOT_EXPR:
-         in_p = ! in_p, exp = arg0;
-         continue;
-
-       case EQ_EXPR: case NE_EXPR:
-       case LT_EXPR: case LE_EXPR: case GE_EXPR: case GT_EXPR:
-         /* We can only do something if the range is testing for zero
-            and if the second operand is an integer constant.  Note that
-            saying something is "in" the range we make is done by
-            complementing IN_P since it will set in the initial case of
-            being not equal to zero; "out" is leaving it alone.  */
-         if (low == 0 || high == 0
-             || ! integer_zerop (low) || ! integer_zerop (high)
-             || TREE_CODE (arg1) != INTEGER_CST)
-           break;
+         if (! merge_ranges (&n_in_p, &n_low, &n_high,
+                             in_p, low, high, 1,
+                             build_int_cst (arg0_type, 0),
+                             NULL_TREE))
+           return NULL_TREE;
 
-         switch (code)
-           {
-           case NE_EXPR:  /* - [c, c]  */
-             low = high = arg1;
-             break;
-           case EQ_EXPR:  /* + [c, c]  */
-             in_p = ! in_p, low = high = arg1;
-             break;
-           case GT_EXPR:  /* - [-, c] */
-             low = 0, high = arg1;
-             break;
-           case GE_EXPR:  /* + [c, -] */
-             in_p = ! in_p, low = arg1, high = 0;
-             break;
-           case LT_EXPR:  /* - [c, -] */
-             low = arg1, high = 0;
-             break;
-           case LE_EXPR:  /* + [-, c] */
-             in_p = ! in_p, low = 0, high = arg1;
-             break;
-           default:
-             gcc_unreachable ();
-           }
+         in_p = n_in_p, low = n_low, high = n_high;
 
-         /* If this is an unsigned comparison, we also know that EXP is
-            greater than or equal to zero.  We base the range tests we make
-            on that fact, so we record it here so we can parse existing
-            range tests.  We test arg0_type since often the return type
-            of, e.g. EQ_EXPR, is boolean.  */
-         if (TYPE_UNSIGNED (arg0_type) && (low == 0 || high == 0))
+         /* If the high bound is missing, but we have a nonzero low
+            bound, reverse the range so it goes from zero to the low bound
+            minus 1.  */
+         if (high == 0 && low && ! integer_zerop (low))
            {
-             if (! merge_ranges (&n_in_p, &n_low, &n_high,
-                                 in_p, low, high, 1,
-                                 build_int_cst (arg0_type, 0),
-                                 NULL_TREE))
-               break;
-
-             in_p = n_in_p, low = n_low, high = n_high;
-
-             /* If the high bound is missing, but we have a nonzero low
-                bound, reverse the range so it goes from zero to the low bound
-                minus 1.  */
-             if (high == 0 && low && ! integer_zerop (low))
-               {
-                 in_p = ! in_p;
-                 high = range_binop (MINUS_EXPR, NULL_TREE, low, 0,
-                                     integer_one_node, 0);
-                 low = build_int_cst (arg0_type, 0);
-               }
+             in_p = ! in_p;
+             high = range_binop (MINUS_EXPR, NULL_TREE, low, 0,
+                                 integer_one_node, 0);
+             low = build_int_cst (arg0_type, 0);
            }
+       }
 
-         exp = arg0;
-         continue;
-
-       case NEGATE_EXPR:
-         /* (-x) IN [a,b] -> x in [-b, -a]  */
-         n_low = range_binop (MINUS_EXPR, exp_type,
-                              build_int_cst (exp_type, 0),
-                              0, high, 1);
-         n_high = range_binop (MINUS_EXPR, exp_type,
-                               build_int_cst (exp_type, 0),
-                               0, low, 0);
-         low = n_low, high = n_high;
-         exp = arg0;
-         continue;
-
-       case BIT_NOT_EXPR:
-         /* ~ X -> -X - 1  */
-         exp = build2 (MINUS_EXPR, exp_type, negate_expr (arg0),
-                       build_int_cst (exp_type, 1));
-         SET_EXPR_LOCATION (exp, loc);
-         continue;
-
-       case PLUS_EXPR:  case MINUS_EXPR:
-         if (TREE_CODE (arg1) != INTEGER_CST)
-           break;
+      *p_low = low;
+      *p_high = high;
+      *p_in_p = in_p;
+      return arg0;
 
-         /* If flag_wrapv and ARG0_TYPE is signed, then we cannot
-            move a constant to the other side.  */
-         if (!TYPE_UNSIGNED (arg0_type)
-             && !TYPE_OVERFLOW_UNDEFINED (arg0_type))
-           break;
+    case NEGATE_EXPR:
+      /* (-x) IN [a,b] -> x in [-b, -a]  */
+      n_low = range_binop (MINUS_EXPR, exp_type,
+                          build_int_cst (exp_type, 0),
+                          0, high, 1);
+      n_high = range_binop (MINUS_EXPR, exp_type,
+                           build_int_cst (exp_type, 0),
+                           0, low, 0);
+      if (n_high != 0 && TREE_OVERFLOW (n_high))
+       return NULL_TREE;
+      goto normalize;
 
-         /* 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
-            and this is exactly the right thing.  */
-         n_low = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR,
-                              arg0_type, low, 0, arg1, 0);
-         n_high = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR,
-                               arg0_type, high, 1, arg1, 0);
-         if ((n_low != 0 && TREE_OVERFLOW (n_low))
-             || (n_high != 0 && TREE_OVERFLOW (n_high)))
-           break;
+    case BIT_NOT_EXPR:
+      /* ~ X -> -X - 1  */
+      return build2_loc (loc, MINUS_EXPR, exp_type, negate_expr (arg0),
+                        build_int_cst (exp_type, 1));
 
-         if (TYPE_OVERFLOW_UNDEFINED (arg0_type))
-           *strict_overflow_p = true;
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      if (TREE_CODE (arg1) != INTEGER_CST)
+       return NULL_TREE;
 
-         /* Check for an unsigned range which has wrapped around the maximum
-            value thus making n_high < n_low, and normalize it.  */
-         if (n_low && n_high && tree_int_cst_lt (n_high, n_low))
-           {
-             low = range_binop (PLUS_EXPR, arg0_type, n_high, 0,
-                                integer_one_node, 0);
-             high = range_binop (MINUS_EXPR, arg0_type, n_low, 0,
-                                 integer_one_node, 0);
+      /* If flag_wrapv and ARG0_TYPE is signed, then we cannot
+        move a constant to the other side.  */
+      if (!TYPE_UNSIGNED (arg0_type)
+         && !TYPE_OVERFLOW_UNDEFINED (arg0_type))
+       return NULL_TREE;
 
-             /* If the range is of the form +/- [ x+1, x ], we won't
-                be able to normalize it.  But then, it represents the
-                whole range or the empty set, so make it
-                +/- [ -, - ].  */
-             if (tree_int_cst_equal (n_low, low)
-                 && tree_int_cst_equal (n_high, high))
-               low = high = 0;
-             else
-               in_p = ! in_p;
-           }
-         else
-           low = n_low, high = n_high;
+      /* 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
+        and this is exactly the right thing.  */
+      n_low = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR,
+                          arg0_type, low, 0, arg1, 0);
+      n_high = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR,
+                           arg0_type, high, 1, arg1, 0);
+      if ((n_low != 0 && TREE_OVERFLOW (n_low))
+         || (n_high != 0 && TREE_OVERFLOW (n_high)))
+       return NULL_TREE;
 
-         exp = arg0;
-         continue;
+      if (TYPE_OVERFLOW_UNDEFINED (arg0_type))
+       *strict_overflow_p = true;
 
-       CASE_CONVERT: case NON_LVALUE_EXPR:
-         if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type))
-           break;
+      normalize:
+       /* Check for an unsigned range which has wrapped around the maximum
+          value thus making n_high < n_low, and normalize it.  */
+       if (n_low && n_high && tree_int_cst_lt (n_high, n_low))
+         {
+           low = range_binop (PLUS_EXPR, arg0_type, n_high, 0,
+                              integer_one_node, 0);
+           high = range_binop (MINUS_EXPR, arg0_type, n_low, 0,
+                               integer_one_node, 0);
+
+           /* If the range is of the form +/- [ x+1, x ], we won't
+              be able to normalize it.  But then, it represents the
+              whole range or the empty set, so make it
+              +/- [ -, - ].  */
+           if (tree_int_cst_equal (n_low, low)
+               && tree_int_cst_equal (n_high, high))
+             low = high = 0;
+           else
+             in_p = ! in_p;
+         }
+       else
+         low = n_low, high = n_high;
 
-         if (! INTEGRAL_TYPE_P (arg0_type)
-             || (low != 0 && ! int_fits_type_p (low, arg0_type))
-             || (high != 0 && ! int_fits_type_p (high, arg0_type)))
-           break;
+       *p_low = low;
+       *p_high = high;
+       *p_in_p = in_p;
+       return arg0;
+
+    CASE_CONVERT:
+    case NON_LVALUE_EXPR:
+      if (TYPE_PRECISION (arg0_type) > TYPE_PRECISION (exp_type))
+       return NULL_TREE;
 
-         n_low = low, n_high = high;
+      if (! INTEGRAL_TYPE_P (arg0_type)
+         || (low != 0 && ! int_fits_type_p (low, arg0_type))
+         || (high != 0 && ! int_fits_type_p (high, arg0_type)))
+       return NULL_TREE;
 
-         if (n_low != 0)
-           n_low = fold_convert_loc (loc, arg0_type, n_low);
+      n_low = low, n_high = high;
 
-         if (n_high != 0)
-           n_high = fold_convert_loc (loc, arg0_type, n_high);
+      if (n_low != 0)
+       n_low = fold_convert_loc (loc, arg0_type, n_low);
 
+      if (n_high != 0)
+       n_high = fold_convert_loc (loc, arg0_type, n_high);
 
-         /* If we're converting arg0 from an unsigned type, to exp,
-            a signed type,  we will be doing the comparison as unsigned.
-            The tests above have already verified that LOW and HIGH
-            are both positive.
+      /* If we're converting arg0 from an unsigned type, to exp,
+        a signed type,  we will be doing the comparison as unsigned.
+        The tests above have already verified that LOW and HIGH
+        are both positive.
 
-            So we have to ensure that we will handle large unsigned
-            values the same way that the current signed bounds treat
-            negative values.  */
+        So we have to ensure that we will handle large unsigned
+        values the same way that the current signed bounds treat
+        negative values.  */
 
-         if (!TYPE_UNSIGNED (exp_type) && TYPE_UNSIGNED (arg0_type))
-           {
-             tree high_positive;
-             tree equiv_type;
-             /* For fixed-point modes, we need to pass the saturating flag
-                as the 2nd parameter.  */
-             if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (arg0_type)))
-               equiv_type = lang_hooks.types.type_for_mode
-                            (TYPE_MODE (arg0_type),
-                             TYPE_SATURATING (arg0_type));
-             else
-               equiv_type = lang_hooks.types.type_for_mode
-                            (TYPE_MODE (arg0_type), 1);
-
-             /* A range without an upper bound is, naturally, unbounded.
-                Since convert would have cropped a very large value, use
-                the max value for the destination type.  */
-             high_positive
-               = TYPE_MAX_VALUE (equiv_type) ? TYPE_MAX_VALUE (equiv_type)
-               : TYPE_MAX_VALUE (arg0_type);
-
-             if (TYPE_PRECISION (exp_type) == TYPE_PRECISION (arg0_type))
-               high_positive = fold_build2_loc (loc, RSHIFT_EXPR, arg0_type,
+      if (!TYPE_UNSIGNED (exp_type) && TYPE_UNSIGNED (arg0_type))
+       {
+         tree high_positive;
+         tree equiv_type;
+         /* For fixed-point modes, we need to pass the saturating flag
+            as the 2nd parameter.  */
+         if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (arg0_type)))
+           equiv_type
+             = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type),
+                                               TYPE_SATURATING (arg0_type));
+         else
+           equiv_type
+             = lang_hooks.types.type_for_mode (TYPE_MODE (arg0_type), 1);
+
+         /* A range without an upper bound is, naturally, unbounded.
+            Since convert would have cropped a very large value, use
+            the max value for the destination type.  */
+         high_positive
+           = TYPE_MAX_VALUE (equiv_type) ? TYPE_MAX_VALUE (equiv_type)
+             : TYPE_MAX_VALUE (arg0_type);
+
+         if (TYPE_PRECISION (exp_type) == TYPE_PRECISION (arg0_type))
+           high_positive = fold_build2_loc (loc, RSHIFT_EXPR, arg0_type,
                                             fold_convert_loc (loc, arg0_type,
                                                               high_positive),
                                             build_int_cst (arg0_type, 1));
 
-             /* If the low bound is specified, "and" the range with the
-                range for which the original unsigned value will be
-                positive.  */
-             if (low != 0)
-               {
-                 if (! merge_ranges (&n_in_p, &n_low, &n_high,
-                                     1, n_low, n_high, 1,
-                                     fold_convert_loc (loc, arg0_type,
-                                                       integer_zero_node),
-                                     high_positive))
-                   break;
+         /* If the low bound is specified, "and" the range with the
+            range for which the original unsigned value will be
+            positive.  */
+         if (low != 0)
+           {
+             if (! merge_ranges (&n_in_p, &n_low, &n_high, 1, n_low, n_high,
+                                 1, fold_convert_loc (loc, arg0_type,
+                                                      integer_zero_node),
+                                 high_positive))
+               return NULL_TREE;
 
-                 in_p = (n_in_p == in_p);
-               }
-             else
-               {
-                 /* Otherwise, "or" the range with the range of the input
-                    that will be interpreted as negative.  */
-                 if (! merge_ranges (&n_in_p, &n_low, &n_high,
-                                     0, n_low, n_high, 1,
-                                     fold_convert_loc (loc, arg0_type,
-                                                       integer_zero_node),
-                                     high_positive))
-                   break;
+             in_p = (n_in_p == in_p);
+           }
+         else
+           {
+             /* Otherwise, "or" the range with the range of the input
+                that will be interpreted as negative.  */
+             if (! merge_ranges (&n_in_p, &n_low, &n_high, 0, n_low, n_high,
+                                 1, fold_convert_loc (loc, arg0_type,
+                                                      integer_zero_node),
+                                 high_positive))
+               return NULL_TREE;
 
-                 in_p = (in_p != n_in_p);
-               }
+             in_p = (in_p != n_in_p);
            }
+       }
 
-         exp = arg0;
-         low = n_low, high = n_high;
-         continue;
+      *p_low = n_low;
+      *p_high = n_high;
+      *p_in_p = in_p;
+      return arg0;
 
-       default:
-         break;
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Given EXP, a logical expression, set the range it is testing into
+   variables denoted by PIN_P, PLOW, and PHIGH.  Return the expression
+   actually being tested.  *PLOW and *PHIGH will be made of the same
+   type as the returned expression.  If EXP is not a comparison, we
+   will most likely not be returning a useful value and range.  Set
+   *STRICT_OVERFLOW_P to true if the return value is only valid
+   because signed overflow is undefined; otherwise, do not change
+   *STRICT_OVERFLOW_P.  */
+
+tree
+make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
+           bool *strict_overflow_p)
+{
+  enum tree_code code;
+  tree arg0, arg1 = NULL_TREE;
+  tree exp_type, nexp;
+  int in_p;
+  tree low, high;
+  location_t loc = EXPR_LOCATION (exp);
+
+  /* Start with simply saying "EXP != 0" and then look at the code of EXP
+     and see if we can refine the range.  Some of the cases below may not
+     happen, but it doesn't seem worth worrying about this.  We "continue"
+     the outer loop when we've changed something; otherwise we "break"
+     the switch, which will "break" the while.  */
+
+  in_p = 0;
+  low = high = build_int_cst (TREE_TYPE (exp), 0);
+
+  while (1)
+    {
+      code = TREE_CODE (exp);
+      exp_type = TREE_TYPE (exp);
+      arg0 = NULL_TREE;
+
+      if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+       {
+         if (TREE_OPERAND_LENGTH (exp) > 0)
+           arg0 = TREE_OPERAND (exp, 0);
+         if (TREE_CODE_CLASS (code) == tcc_binary
+             || TREE_CODE_CLASS (code) == tcc_comparison
+             || (TREE_CODE_CLASS (code) == tcc_expression
+                 && TREE_OPERAND_LENGTH (exp) > 1))
+           arg1 = TREE_OPERAND (exp, 1);
        }
+      if (arg0 == NULL_TREE)
+       break;
 
-      break;
+      nexp = make_range_step (loc, code, arg0, arg1, exp_type, &low,
+                             &high, &in_p, strict_overflow_p);
+      if (nexp == NULL_TREE)
+       break;
+      exp = nexp;
     }
 
   /* If EXP is a constant, we can evaluate whether this is true or false.  */
@@ -4284,18 +4256,16 @@ build_range_check (location_t loc, tree type, tree exp, int in_p,
   low = fold_convert_loc (loc, etype, low);
   exp = fold_convert_loc (loc, etype, exp);
 
-  value = const_binop (MINUS_EXPR, high, low, 0);
+  value = const_binop (MINUS_EXPR, high, low);
 
 
   if (POINTER_TYPE_P (etype))
     {
       if (value != 0 && !TREE_OVERFLOW (value))
        {
-         low = fold_convert_loc (loc, sizetype, low);
-         low = fold_build1_loc (loc, NEGATE_EXPR, sizetype, low);
+         low = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (low), low);
           return build_range_check (loc, type,
-                                   fold_build2_loc (loc, POINTER_PLUS_EXPR,
-                                                etype, exp, low),
+                                   fold_build_pointer_plus_loc (loc, exp, low),
                                    1, build_int_cst (etype, 0), value);
        }
       return 0;
@@ -4787,7 +4757,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
                               OEP_ONLY_CONST)
            && operand_equal_p (arg01,
                                const_binop (PLUS_EXPR, arg2,
-                                            build_int_cst (type, 1), 0),
+                                            build_int_cst (type, 1)),
                                OEP_ONLY_CONST))
          {
            tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
@@ -4805,7 +4775,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
                               OEP_ONLY_CONST)
            && operand_equal_p (arg01,
                                const_binop (MINUS_EXPR, arg2,
-                                            build_int_cst (type, 1), 0),
+                                            build_int_cst (type, 1)),
                                OEP_ONLY_CONST))
          {
            tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
@@ -4823,7 +4793,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
                               OEP_ONLY_CONST)
            && operand_equal_p (arg01,
                                const_binop (MINUS_EXPR, arg2,
-                                            build_int_cst (type, 1), 0),
+                                            build_int_cst (type, 1)),
                                OEP_ONLY_CONST))
          {
            tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
@@ -4839,7 +4809,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
                               OEP_ONLY_CONST)
            && operand_equal_p (arg01,
                                const_binop (PLUS_EXPR, arg2,
-                                            build_int_cst (type, 1), 0),
+                                            build_int_cst (type, 1)),
                                OEP_ONLY_CONST))
          {
            tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
@@ -4895,7 +4865,7 @@ fold_range_test (location_t loc, enum tree_code code, tree type,
   if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0))
       && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
                       in1_p, low1, high1)
-      && 0 != (tem = (build_range_check (UNKNOWN_LOCATION, type,
+      && 0 != (tem = (build_range_check (loc, type,
                                         lhs != 0 ? lhs
                                         : rhs != 0 ? rhs : integer_zero_node,
                                         in_p, low, high))))
@@ -4918,16 +4888,12 @@ fold_range_test (location_t loc, enum tree_code code, tree type,
         unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in
         which cases we can't do this.  */
       if (simple_operand_p (lhs))
-       {
-         tem = build2 (code == TRUTH_ANDIF_EXPR
-                       ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
-                       type, op0, op1);
-         SET_EXPR_LOCATION (tem, loc);
-         return tem;
-       }
+       return build2_loc (loc, code == TRUTH_ANDIF_EXPR
+                          ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+                          type, op0, op1);
 
-      else if (lang_hooks.decls.global_bindings_p () == 0
-              && ! CONTAINS_PLACEHOLDER_P (lhs))
+      else if (!lang_hooks.decls.global_bindings_p ()
+              && !CONTAINS_PLACEHOLDER_P (lhs))
        {
          tree common = save_expr (lhs);
 
@@ -4941,11 +4907,9 @@ fold_range_test (location_t loc, enum tree_code code, tree type,
              if (strict_overflow_p)
                fold_overflow_warning (warnmsg,
                                       WARN_STRICT_OVERFLOW_COMPARISON);
-             tem = build2 (code == TRUTH_ANDIF_EXPR
-                           ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
-                           type, lhs, rhs);
-             SET_EXPR_LOCATION (tem, loc);
-             return tem;
+             return build2_loc (loc, code == TRUTH_ANDIF_EXPR
+                                ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+                                type, lhs, rhs);
            }
        }
     }
@@ -4953,7 +4917,7 @@ fold_range_test (location_t loc, enum tree_code code, tree type,
   return 0;
 }
 \f
-/* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P
+/* Subroutine for fold_truth_andor_1: C is an INTEGER_CST interpreted as a P
    bit value.  Arrange things so the extra bits will be set to zero if and
    only if C is signed-extended to its full width.  If MASK is nonzero,
    it is an INTEGER_CST that should be AND'ed with the extra bits.  */
@@ -4971,8 +4935,8 @@ unextend (tree c, int p, int unsignedp, tree mask)
   /* We work by getting just the sign bit into the low-order bit, then
      into the high-order bit, then sign-extend.  We then XOR that value
      with C.  */
-  temp = const_binop (RSHIFT_EXPR, c, size_int (p - 1), 0);
-  temp = const_binop (BIT_AND_EXPR, temp, size_int (1), 0);
+  temp = const_binop (RSHIFT_EXPR, c, size_int (p - 1));
+  temp = const_binop (BIT_AND_EXPR, temp, size_int (1));
 
   /* We must use a signed type in order to get an arithmetic right shift.
      However, we must also avoid introducing accidental overflows, so that
@@ -4983,20 +4947,88 @@ unextend (tree c, int p, int unsignedp, tree mask)
   if (TYPE_UNSIGNED (type))
     temp = fold_convert (signed_type_for (type), temp);
 
-  temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1), 0);
-  temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1), 0);
+  temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1));
+  temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1));
   if (mask != 0)
     temp = const_binop (BIT_AND_EXPR, temp,
-                       fold_convert (TREE_TYPE (c), mask),
-                       0);
+                       fold_convert (TREE_TYPE (c), mask));
   /* If necessary, convert the type back to match the type of C.  */
   if (TYPE_UNSIGNED (type))
     temp = fold_convert (type, temp);
 
-  return fold_convert (type,
-                      const_binop (BIT_XOR_EXPR, c, temp, 0));
+  return fold_convert (type, const_binop (BIT_XOR_EXPR, c, temp));
 }
 \f
+/* For an expression that has the form
+     (A && B) || ~B
+   or
+     (A || B) && ~B,
+   we can drop one of the inner expressions and simplify to
+     A || ~B
+   or
+     A && ~B
+   LOC is the location of the resulting expression.  OP is the inner 
+   logical operation; the left-hand side in the examples above, while CMPOP
+   is the right-hand side.  RHS_ONLY is used to prevent us from accidentally
+   removing a condition that guards another, as in
+     (A != NULL && A->...) || A == NULL
+   which we must not transform.  If RHS_ONLY is true, only eliminate the
+   right-most operand of the inner logical operation.  */
+
+static tree
+merge_truthop_with_opposite_arm (location_t loc, tree op, tree cmpop,
+                                bool rhs_only)
+{
+  tree type = TREE_TYPE (cmpop);
+  enum tree_code code = TREE_CODE (cmpop);
+  enum tree_code truthop_code = TREE_CODE (op);
+  tree lhs = TREE_OPERAND (op, 0);
+  tree rhs = TREE_OPERAND (op, 1);
+  tree orig_lhs = lhs, orig_rhs = rhs;
+  enum tree_code rhs_code = TREE_CODE (rhs);
+  enum tree_code lhs_code = TREE_CODE (lhs);
+  enum tree_code inv_code;
+
+  if (TREE_SIDE_EFFECTS (op) || TREE_SIDE_EFFECTS (cmpop))
+    return NULL_TREE;
+
+  if (TREE_CODE_CLASS (code) != tcc_comparison)
+    return NULL_TREE;
+
+  if (rhs_code == truthop_code)
+    {
+      tree newrhs = merge_truthop_with_opposite_arm (loc, rhs, cmpop, rhs_only);
+      if (newrhs != NULL_TREE)
+       {
+         rhs = newrhs;
+         rhs_code = TREE_CODE (rhs);
+       }
+    }
+  if (lhs_code == truthop_code && !rhs_only)
+    {
+      tree newlhs = merge_truthop_with_opposite_arm (loc, lhs, cmpop, false);
+      if (newlhs != NULL_TREE)
+       {
+         lhs = newlhs;
+         lhs_code = TREE_CODE (lhs);
+       }
+    }
+
+  inv_code = invert_tree_comparison (code, HONOR_NANS (TYPE_MODE (type)));
+  if (inv_code == rhs_code
+      && operand_equal_p (TREE_OPERAND (rhs, 0), TREE_OPERAND (cmpop, 0), 0)
+      && operand_equal_p (TREE_OPERAND (rhs, 1), TREE_OPERAND (cmpop, 1), 0))
+    return lhs;
+  if (!rhs_only && inv_code == lhs_code
+      && operand_equal_p (TREE_OPERAND (lhs, 0), TREE_OPERAND (cmpop, 0), 0)
+      && operand_equal_p (TREE_OPERAND (lhs, 1), TREE_OPERAND (cmpop, 1), 0))
+    return rhs;
+  if (rhs != orig_rhs || lhs != orig_lhs)
+    return fold_build2_loc (loc, truthop_code, TREE_TYPE (cmpop),
+                           lhs, rhs);
+  return NULL_TREE;
+}
+
 /* Find ways of folding logical expressions of LHS and RHS:
    Try to merge two comparisons to the same innermost item.
    Look for range tests like "ch >= '0' && ch <= '9'".
@@ -5022,8 +5054,8 @@ unextend (tree c, int p, int unsignedp, tree mask)
    We return the simplified tree or 0 if no optimization is possible.  */
 
 static tree
-fold_truthop (location_t loc, enum tree_code code, tree truth_type,
-             tree lhs, tree rhs)
+fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
+                   tree lhs, tree rhs)
 {
   /* If this is the "or" of two comparisons, we can do something if
      the comparisons are NE_EXPR.  If this is the "and", we can do something
@@ -5051,8 +5083,6 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
   tree lntype, rntype, result;
   HOST_WIDE_INT first_bit, end_bit;
   int volatilep;
-  tree orig_lhs = lhs, orig_rhs = rhs;
-  enum tree_code orig_code = code;
 
   /* Start by getting the comparison codes.  Fail if anything is volatile.
      If one operand is a BIT_AND_EXPR with the constant one, treat it as if
@@ -5091,7 +5121,6 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
   if (simple_operand_p (ll_arg)
       && simple_operand_p (lr_arg))
     {
-      tree result;
       if (operand_equal_p (ll_arg, rl_arg, 0)
           && operand_equal_p (lr_arg, rr_arg, 0))
        {
@@ -5117,8 +5146,7 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
   /* If the RHS can be evaluated unconditionally and its operands are
      simple, it wins to evaluate the RHS unconditionally on machines
      with expensive branches.  In this case, this isn't a comparison
-     that can be merged.  Avoid doing this if the RHS is a floating-point
-     comparison since those can trap.  */
+     that can be merged.  */
 
   if (BRANCH_COST (optimize_function_for_speed_p (cfun),
                   false) >= 2
@@ -5132,13 +5160,10 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
          && rcode == NE_EXPR && integer_zerop (rr_arg)
          && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)
          && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg)))
-       {
-         result = build2 (NE_EXPR, truth_type,
+       return build2_loc (loc, NE_EXPR, truth_type,
                           build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
                                   ll_arg, rl_arg),
                           build_int_cst (TREE_TYPE (ll_arg), 0));
-         goto fold_truthop_exit;
-       }
 
       /* Convert (a == 0) && (b == 0) into (a | b) == 0.  */
       if (code == TRUTH_AND_EXPR
@@ -5146,23 +5171,10 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
          && rcode == EQ_EXPR && integer_zerop (rr_arg)
          && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg)
          && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg)))
-       {
-         result = build2 (EQ_EXPR, truth_type,
+       return build2_loc (loc, EQ_EXPR, truth_type,
                           build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
                                   ll_arg, rl_arg),
                           build_int_cst (TREE_TYPE (ll_arg), 0));
-         goto fold_truthop_exit;
-       }
-
-      if (LOGICAL_OP_NON_SHORT_CIRCUIT)
-       {
-         if (code != orig_code || lhs != orig_lhs || rhs != orig_rhs)
-           {
-             result = build2 (code, truth_type, lhs, rhs);
-             goto fold_truthop_exit;
-           }
-         return NULL_TREE;
-       }
     }
 
   /* See if the comparisons can be merged.  Then get all the parameters for
@@ -5243,7 +5255,7 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
      to be relative to a field of that size.  */
   first_bit = MIN (ll_bitpos, rl_bitpos);
   end_bit = MAX (ll_bitpos + ll_bitsize, rl_bitpos + rl_bitsize);
-  lnmode = get_best_mode (end_bit - first_bit, first_bit,
+  lnmode = get_best_mode (end_bit - first_bit, first_bit, 0, 0,
                          TYPE_ALIGN (TREE_TYPE (ll_inner)), word_mode,
                          volatilep);
   if (lnmode == VOIDmode)
@@ -5261,19 +5273,18 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
     }
 
   ll_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, lntype, ll_mask),
-                        size_int (xll_bitpos), 0);
+                        size_int (xll_bitpos));
   rl_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc, lntype, rl_mask),
-                        size_int (xrl_bitpos), 0);
+                        size_int (xrl_bitpos));
 
   if (l_const)
     {
       l_const = fold_convert_loc (loc, lntype, l_const);
       l_const = unextend (l_const, ll_bitsize, ll_unsignedp, ll_and_mask);
-      l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos), 0);
+      l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos));
       if (! integer_zerop (const_binop (BIT_AND_EXPR, l_const,
                                        fold_build1_loc (loc, BIT_NOT_EXPR,
-                                                    lntype, ll_mask),
-                                       0)))
+                                                    lntype, ll_mask))))
        {
          warning (0, "comparison is always %d", wanted_code == NE_EXPR);
 
@@ -5284,11 +5295,10 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
     {
       r_const = fold_convert_loc (loc, lntype, r_const);
       r_const = unextend (r_const, rl_bitsize, rl_unsignedp, rl_and_mask);
-      r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos), 0);
+      r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos));
       if (! integer_zerop (const_binop (BIT_AND_EXPR, r_const,
                                        fold_build1_loc (loc, BIT_NOT_EXPR,
-                                                    lntype, rl_mask),
-                                       0)))
+                                                    lntype, rl_mask))))
        {
          warning (0, "comparison is always %d", wanted_code == NE_EXPR);
 
@@ -5310,7 +5320,7 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
 
       first_bit = MIN (lr_bitpos, rr_bitpos);
       end_bit = MAX (lr_bitpos + lr_bitsize, rr_bitpos + rr_bitsize);
-      rnmode = get_best_mode (end_bit - first_bit, first_bit,
+      rnmode = get_best_mode (end_bit - first_bit, first_bit, 0, 0,
                              TYPE_ALIGN (TREE_TYPE (lr_inner)), word_mode,
                              volatilep);
       if (rnmode == VOIDmode)
@@ -5329,18 +5339,18 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
 
       lr_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc,
                                                            rntype, lr_mask),
-                            size_int (xlr_bitpos), 0);
+                            size_int (xlr_bitpos));
       rr_mask = const_binop (LSHIFT_EXPR, fold_convert_loc (loc,
                                                            rntype, rr_mask),
-                            size_int (xrr_bitpos), 0);
+                            size_int (xrr_bitpos));
 
       /* Make a mask that corresponds to both fields being compared.
         Do this for both items being compared.  If the operands are the
         same size and the bits being compared are in the same position
         then we can do this by masking both and comparing the masked
         results.  */
-      ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
-      lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask, 0);
+      ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
+      lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask);
       if (lnbitsize == rnbitsize && xll_bitpos == xlr_bitpos)
        {
          lhs = make_bit_field_ref (loc, ll_inner, lntype, lnbitsize, lnbitpos,
@@ -5353,8 +5363,7 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
          if (! all_ones_mask_p (lr_mask, rnbitsize))
            rhs = build2 (BIT_AND_EXPR, rntype, rhs, lr_mask);
 
-         result = build2 (wanted_code, truth_type, lhs, rhs);
-         goto fold_truthop_exit;
+         return build2_loc (loc, wanted_code, truth_type, lhs, rhs);
        }
 
       /* There is still another way we can do something:  If both pairs of
@@ -5379,9 +5388,9 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
                                    MIN (lr_bitpos, rr_bitpos), lr_unsignedp);
 
          ll_mask = const_binop (RSHIFT_EXPR, ll_mask,
-                                size_int (MIN (xll_bitpos, xrl_bitpos)), 0);
+                                size_int (MIN (xll_bitpos, xrl_bitpos)));
          lr_mask = const_binop (RSHIFT_EXPR, lr_mask,
-                                size_int (MIN (xlr_bitpos, xrr_bitpos)), 0);
+                                size_int (MIN (xlr_bitpos, xrr_bitpos)));
 
          /* Convert to the smaller type before masking out unwanted bits.  */
          type = lntype;
@@ -5407,8 +5416,7 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
          if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize))
            rhs = build2 (BIT_AND_EXPR, type, rhs, lr_mask);
 
-         result = build2 (wanted_code, truth_type, lhs, rhs);
-         goto fold_truthop_exit;
+         return build2_loc (loc, wanted_code, truth_type, lhs, rhs);
        }
 
       return 0;
@@ -5418,10 +5426,10 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
      common between the masks, those bits of the constants must be the same.
      If not, the condition is always false.  Test for this to avoid generating
      incorrect code below.  */
-  result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask, 0);
+  result = const_binop (BIT_AND_EXPR, ll_mask, rl_mask);
   if (! integer_zerop (result)
-      && simple_cst_equal (const_binop (BIT_AND_EXPR, result, l_const, 0),
-                          const_binop (BIT_AND_EXPR, result, r_const, 0)) != 1)
+      && simple_cst_equal (const_binop (BIT_AND_EXPR, result, l_const),
+                          const_binop (BIT_AND_EXPR, result, r_const)) != 1)
     {
       if (wanted_code == NE_EXPR)
        {
@@ -5442,19 +5450,12 @@ fold_truthop (location_t loc, enum tree_code code, tree truth_type,
   result = make_bit_field_ref (loc, ll_inner, lntype, lnbitsize, lnbitpos,
                               ll_unsignedp || rl_unsignedp);
 
-  ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
+  ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
   if (! all_ones_mask_p (ll_mask, lnbitsize))
-    {
-      result = build2 (BIT_AND_EXPR, lntype, result, ll_mask);
-      SET_EXPR_LOCATION (result, loc);
-    }
-
-  result = build2 (wanted_code, truth_type, result,
-                  const_binop (BIT_IOR_EXPR, l_const, r_const, 0));
+    result = build2_loc (loc, BIT_AND_EXPR, lntype, result, ll_mask);
 
- fold_truthop_exit:
-  SET_EXPR_LOCATION (result, loc);
-  return result;
+  return build2_loc (loc, wanted_code, truth_type, result,
+                    const_binop (BIT_IOR_EXPR, l_const, r_const));
 }
 \f
 /* Optimize T, which is a comparison of a MIN_EXPR or MAX_EXPR with a
@@ -5633,9 +5634,9 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
       /* For a constant, we can always simplify if we are a multiply
         or (for divide and modulus) if it is a multiple of our constant.  */
       if (code == MULT_EXPR
-         || integer_zerop (const_binop (TRUNC_MOD_EXPR, t, c, 0)))
+         || integer_zerop (const_binop (TRUNC_MOD_EXPR, t, c)))
        return const_binop (code, fold_convert (ctype, t),
-                           fold_convert (ctype, c), 0);
+                           fold_convert (ctype, c));
       break;
 
     CASE_CONVERT: case NON_LVALUE_EXPR:
@@ -5743,7 +5744,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
          && 0 != (t1 = fold_convert (ctype,
                                      const_binop (LSHIFT_EXPR,
                                                   size_one_node,
-                                                  op1, 0)))
+                                                  op1)))
          && !TREE_OVERFLOW (t1))
        return extract_muldiv (build2 (tcode == LSHIFT_EXPR
                                       ? MULT_EXPR : FLOOR_DIV_EXPR,
@@ -5811,10 +5812,10 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
       /* If it's a multiply or a division/modulus operation of a multiple
          of our constant, do the operation and verify it doesn't overflow.  */
       if (code == MULT_EXPR
-         || integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
+         || integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c)))
        {
          op1 = const_binop (code, fold_convert (ctype, op1),
-                            fold_convert (ctype, c), 0);
+                            fold_convert (ctype, c));
          /* We allow the constant to overflow with wrapping semantics.  */
          if (op1 == 0
              || (TREE_OVERFLOW (op1) && !TYPE_OVERFLOW_WRAPS (ctype)))
@@ -5862,7 +5863,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
              || (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
                  && TYPE_IS_SIZETYPE (TREE_TYPE (t))))
          && TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST
-         && integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
+         && integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c)))
        {
          *strict_overflow_p = true;
          return omit_one_operand (type, integer_zero_node, op0);
@@ -5890,17 +5891,33 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
 
       /* If these are the same operation types, we can associate them
         assuming no overflow.  */
-      if (tcode == code
-         && 0 != (t1 = int_const_binop (MULT_EXPR,
-                                        fold_convert (ctype, op1),
-                                        fold_convert (ctype, c), 1))
-         && 0 != (t1 = force_fit_type_double (ctype, TREE_INT_CST_LOW (t1),
-                                              TREE_INT_CST_HIGH (t1),
-                                              (TYPE_UNSIGNED (ctype)
-                                               && tcode != MULT_EXPR) ? -1 : 1,
-                                              TREE_OVERFLOW (t1)))
-         && !TREE_OVERFLOW (t1))
-       return fold_build2 (tcode, ctype, fold_convert (ctype, op0), t1);
+      if (tcode == code)
+       {
+         double_int mul;
+         int overflow_p;
+         mul = double_int_mul_with_sign
+                 (double_int_ext
+                    (tree_to_double_int (op1),
+                     TYPE_PRECISION (ctype), TYPE_UNSIGNED (ctype)),
+                  double_int_ext
+                    (tree_to_double_int (c),
+                     TYPE_PRECISION (ctype), TYPE_UNSIGNED (ctype)),
+                  false, &overflow_p);
+         overflow_p = (((!TYPE_UNSIGNED (ctype)
+                         || (TREE_CODE (ctype) == INTEGER_TYPE
+                             && TYPE_IS_SIZETYPE (ctype)))
+                        && overflow_p)
+                       | TREE_OVERFLOW (c) | TREE_OVERFLOW (op1));
+         if (!double_int_fits_to_tree_p (ctype, mul)
+             && ((TYPE_UNSIGNED (ctype) && tcode != MULT_EXPR)
+                 || !TYPE_UNSIGNED (ctype)
+                 || (TREE_CODE (ctype) == INTEGER_TYPE
+                     && TYPE_IS_SIZETYPE (ctype))))
+           overflow_p = 1;
+         if (!overflow_p)
+           return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
+                               double_int_to_tree (ctype, mul));
+       }
 
       /* If these operations "cancel" each other, we have the main
         optimizations of this pass, which occur when either constant is a
@@ -5918,23 +5935,23 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
                  && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR
                  && code != MULT_EXPR)))
        {
-         if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
+         if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c)))
            {
              if (TYPE_OVERFLOW_UNDEFINED (ctype))
                *strict_overflow_p = true;
              return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
                                  fold_convert (ctype,
                                                const_binop (TRUNC_DIV_EXPR,
-                                                            op1, c, 0)));
+                                                            op1, c)));
            }
-         else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0)))
+         else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1)))
            {
              if (TYPE_OVERFLOW_UNDEFINED (ctype))
                *strict_overflow_p = true;
              return fold_build2 (code, ctype, fold_convert (ctype, op0),
                                  fold_convert (ctype,
                                                const_binop (TRUNC_DIV_EXPR,
-                                                            c, op1, 0)));
+                                                            c, op1)));
            }
        }
       break;
@@ -5947,17 +5964,22 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
 }
 \f
 /* Return a node which has the indicated constant VALUE (either 0 or
-   1), and is of the indicated TYPE.  */
+   1 for scalars or {-1,-1,..} or {0,0,...} for vectors),
+   and is of the indicated TYPE.  */
 
 tree
-constant_boolean_node (int value, tree type)
+constant_boolean_node (bool value, tree type)
 {
   if (type == integer_type_node)
     return value ? integer_one_node : integer_zero_node;
   else if (type == boolean_type_node)
     return value ? boolean_true_node : boolean_false_node;
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    return build_vector_from_val (type,
+                                 build_int_cst (TREE_TYPE (type),
+                                                value ? -1 : 0));
   else
-    return build_int_cst (type, value);
+    return fold_convert (type, value ? integer_one_node : integer_zero_node);
 }
 
 
@@ -6164,10 +6186,6 @@ fold_mathfn_compare (location_t loc,
                                    build_real (TREE_TYPE (arg), dconst0));
 
              /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large.  */
-             if (lang_hooks.decls.global_bindings_p () != 0
-                 || CONTAINS_PLACEHOLDER_P (arg))
-               return NULL_TREE;
-
              arg = save_expr (arg);
              return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type,
                                  fold_build2_loc (loc, GE_EXPR, type, arg,
@@ -6184,18 +6202,14 @@ fold_mathfn_compare (location_t loc,
                                build_real (TREE_TYPE (arg), c2));
 
          /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
-         if (lang_hooks.decls.global_bindings_p () == 0
-             && ! CONTAINS_PLACEHOLDER_P (arg))
-           {
-             arg = save_expr (arg);
-             return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type,
+         arg = save_expr (arg);
+         return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type,
                                  fold_build2_loc (loc, GE_EXPR, type, arg,
                                               build_real (TREE_TYPE (arg),
                                                           dconst0)),
                                  fold_build2_loc (loc, code, type, arg,
                                               build_real (TREE_TYPE (arg),
                                                           c2)));
-           }
        }
     }
 
@@ -6242,13 +6256,8 @@ fold_inf_compare (location_t loc, enum tree_code code, tree type,
        return omit_one_operand_loc (loc, type, integer_one_node, arg0);
 
       /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
-      if (lang_hooks.decls.global_bindings_p () == 0
-         && ! CONTAINS_PLACEHOLDER_P (arg0))
-       {
-         arg0 = save_expr (arg0);
-         return fold_build2_loc (loc, EQ_EXPR, type, arg0, arg0);
-       }
-      break;
+      arg0 = save_expr (arg0);
+      return fold_build2_loc (loc, EQ_EXPR, type, arg0, arg0);
 
     case EQ_EXPR:
     case GE_EXPR:
@@ -6299,47 +6308,45 @@ fold_div_compare (location_t loc,
   tree prod, tmp, hi, lo;
   tree arg00 = TREE_OPERAND (arg0, 0);
   tree arg01 = TREE_OPERAND (arg0, 1);
-  unsigned HOST_WIDE_INT lpart;
-  HOST_WIDE_INT hpart;
+  double_int val;
   bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
   bool neg_overflow;
   int overflow;
 
   /* We have to do this the hard way to detect unsigned overflow.
-     prod = int_const_binop (MULT_EXPR, arg01, arg1, 0);  */
+     prod = int_const_binop (MULT_EXPR, arg01, arg1);  */
   overflow = mul_double_with_sign (TREE_INT_CST_LOW (arg01),
                                   TREE_INT_CST_HIGH (arg01),
                                   TREE_INT_CST_LOW (arg1),
                                   TREE_INT_CST_HIGH (arg1),
-                                  &lpart, &hpart, unsigned_p);
-  prod = force_fit_type_double (TREE_TYPE (arg00), lpart, hpart,
-                               -1, overflow);
+                                  &val.low, &val.high, unsigned_p);
+  prod = force_fit_type_double (TREE_TYPE (arg00), val, -1, overflow);
   neg_overflow = false;
 
   if (unsigned_p)
     {
       tmp = int_const_binop (MINUS_EXPR, arg01,
-                             build_int_cst (TREE_TYPE (arg01), 1), 0);
+                             build_int_cst (TREE_TYPE (arg01), 1));
       lo = prod;
 
-      /* Likewise hi = int_const_binop (PLUS_EXPR, prod, tmp, 0).  */
+      /* Likewise hi = int_const_binop (PLUS_EXPR, prod, tmp).  */
       overflow = add_double_with_sign (TREE_INT_CST_LOW (prod),
                                       TREE_INT_CST_HIGH (prod),
                                       TREE_INT_CST_LOW (tmp),
                                       TREE_INT_CST_HIGH (tmp),
-                                      &lpart, &hpart, unsigned_p);
-      hi = force_fit_type_double (TREE_TYPE (arg00), lpart, hpart,
+                                      &val.low, &val.high, unsigned_p);
+      hi = force_fit_type_double (TREE_TYPE (arg00), val,
                                  -1, overflow | TREE_OVERFLOW (prod));
     }
   else if (tree_int_cst_sgn (arg01) >= 0)
     {
       tmp = int_const_binop (MINUS_EXPR, arg01,
-                            build_int_cst (TREE_TYPE (arg01), 1), 0);
+                            build_int_cst (TREE_TYPE (arg01), 1));
       switch (tree_int_cst_sgn (arg1))
        {
        case -1:
          neg_overflow = true;
-         lo = int_const_binop (MINUS_EXPR, prod, tmp, 0);
+         lo = int_const_binop (MINUS_EXPR, prod, tmp);
          hi = prod;
          break;
 
@@ -6349,7 +6356,7 @@ fold_div_compare (location_t loc,
          break;
 
        case  1:
-          hi = int_const_binop (PLUS_EXPR, prod, tmp, 0);
+          hi = int_const_binop (PLUS_EXPR, prod, tmp);
          lo = prod;
          break;
 
@@ -6363,11 +6370,11 @@ fold_div_compare (location_t loc,
       code = swap_tree_comparison (code);
 
       tmp = int_const_binop (PLUS_EXPR, arg01,
-                            build_int_cst (TREE_TYPE (arg01), 1), 0);
+                            build_int_cst (TREE_TYPE (arg01), 1));
       switch (tree_int_cst_sgn (arg1))
        {
        case -1:
-         hi = int_const_binop (MINUS_EXPR, prod, tmp, 0);
+         hi = int_const_binop (MINUS_EXPR, prod, tmp);
          lo = prod;
          break;
 
@@ -6378,7 +6385,7 @@ fold_div_compare (location_t loc,
 
        case  1:
          neg_overflow = true;
-         lo = int_const_binop (PLUS_EXPR, prod, tmp, 0);
+         lo = int_const_binop (PLUS_EXPR, prod, tmp);
          hi = prod;
          break;
 
@@ -6781,9 +6788,8 @@ fold_sign_changed_comparison (location_t loc, enum tree_code code, tree type,
     return NULL_TREE;
 
   if (TREE_CODE (arg1) == INTEGER_CST)
-    arg1 = force_fit_type_double (inner_type, TREE_INT_CST_LOW (arg1),
-                                 TREE_INT_CST_HIGH (arg1), 0,
-                                 TREE_OVERFLOW (arg1));
+    arg1 = force_fit_type_double (inner_type, tree_to_double_int (arg1),
+                                 0, TREE_OVERFLOW (arg1));
   else
     arg1 = fold_convert_loc (loc, inner_type, arg1);
 
@@ -6900,6 +6906,60 @@ try_move_mult_to_index (location_t loc, tree addr, tree op1)
 
          break;
        }
+      else if (TREE_CODE (ref) == COMPONENT_REF
+              && TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
+       {
+         tree domain;
+
+         /* Remember if this was a multi-dimensional array.  */
+         if (TREE_CODE (TREE_OPERAND (ref, 0)) == ARRAY_REF)
+           mdim = true;
+
+         domain = TYPE_DOMAIN (TREE_TYPE (ref));
+         if (! domain)
+           continue;
+         itype = TREE_TYPE (domain);
+
+         step = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ref)));
+         if (TREE_CODE (step) != INTEGER_CST)
+           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, op1, step);
+             if (! tmp)
+               continue;
+             delta = tmp;
+           }
+
+         /* Only fold here if we can verify we do not overflow one
+            dimension of a multi-dimensional array.  */
+         if (mdim)
+           {
+             tree tmp;
+
+             if (!TYPE_MIN_VALUE (domain)
+                 || !TYPE_MAX_VALUE (domain)
+                 || TREE_CODE (TYPE_MAX_VALUE (domain)) != INTEGER_CST)
+               continue;
+
+             tmp = fold_binary_loc (loc, PLUS_EXPR, itype,
+                                    fold_convert_loc (loc, itype,
+                                                      TYPE_MIN_VALUE (domain)),
+                                    fold_convert_loc (loc, itype, delta));
+             if (TREE_CODE (tmp) != INTEGER_CST
+                 || tree_int_cst_lt (TYPE_MAX_VALUE (domain), tmp))
+               continue;
+           }
+
+         break;
+       }
       else
        mdim = false;
 
@@ -6922,12 +6982,29 @@ try_move_mult_to_index (location_t loc, tree addr, tree op1)
       pos = TREE_OPERAND (pos, 0);
     }
 
-  TREE_OPERAND (pos, 1) = fold_build2_loc (loc, PLUS_EXPR, itype,
-                                      fold_convert_loc (loc, itype,
-                                                        TREE_OPERAND (pos, 1)),
-                                      fold_convert_loc (loc, itype, delta));
-
-  return fold_build1_loc (loc, ADDR_EXPR, TREE_TYPE (addr), ret);
+  if (TREE_CODE (ref) == ARRAY_REF)
+    {
+      TREE_OPERAND (pos, 1)
+       = fold_build2_loc (loc, PLUS_EXPR, itype,
+                          fold_convert_loc (loc, itype, TREE_OPERAND (pos, 1)),
+                          fold_convert_loc (loc, itype, delta));
+      return fold_build1_loc (loc, ADDR_EXPR, TREE_TYPE (addr), ret);
+    }
+  else if (TREE_CODE (ref) == COMPONENT_REF)
+    {
+      gcc_assert (ret == pos);
+      ret = build4_loc (loc, ARRAY_REF, TREE_TYPE (TREE_TYPE (ref)), ret,
+                       fold_build2_loc
+                         (loc, PLUS_EXPR, itype,
+                          fold_convert_loc (loc, itype,
+                                            TYPE_MIN_VALUE
+                                              (TYPE_DOMAIN (TREE_TYPE (ref)))),
+                          fold_convert_loc (loc, itype, delta)),
+                       NULL_TREE, NULL_TREE);
+      return build_fold_addr_expr_loc (loc, ret);
+    }
+  else
+    gcc_unreachable ();
 }
 
 
@@ -7070,8 +7147,7 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
       int11 = TREE_INT_CST_LOW (arg11);
 
       /* Move min of absolute values to int11.  */
-      if ((int01 >= 0 ? int01 : -int01)
-         < (int11 >= 0 ? int11 : -int11))
+      if (absu_hwi (int01) < absu_hwi (int11))
         {
          tmp = int01, int01 = int11, int11 = tmp;
          alt0 = arg00, arg00 = arg10, arg10 = alt0;
@@ -7081,7 +7157,7 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
       else
        maybe_same = arg11;
 
-      if (exact_log2 (abs (int11)) > 0 && int01 % int11 == 0
+      if (exact_log2 (absu_hwi (int11)) > 0 && int01 % int11 == 0
          /* The remainder should not be a constant, otherwise we
             end up folding i * 4 + 2 to (i * 2 + 1) * 2 which has
             increased the number of multiplications necessary.  */
@@ -7338,13 +7414,14 @@ native_interpret_int (tree type, const unsigned char *ptr, int len)
   int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
   int byte, offset, word, words;
   unsigned char value;
-  unsigned int HOST_WIDE_INT lo = 0;
-  HOST_WIDE_INT hi = 0;
+  double_int result;
 
   if (total_bytes > len)
     return NULL_TREE;
   if (total_bytes * BITS_PER_UNIT > 2 * HOST_BITS_PER_WIDE_INT)
     return NULL_TREE;
+
+  result = double_int_zero;
   words = total_bytes / UNITS_PER_WORD;
 
   for (byte = 0; byte < total_bytes; byte++)
@@ -7366,13 +7443,13 @@ native_interpret_int (tree type, const unsigned char *ptr, int len)
       value = ptr[offset];
 
       if (bitpos < HOST_BITS_PER_WIDE_INT)
-       lo |= (unsigned HOST_WIDE_INT) value << bitpos;
+       result.low |= (unsigned HOST_WIDE_INT) value << bitpos;
       else
-       hi |= (unsigned HOST_WIDE_INT) value
-             << (bitpos - HOST_BITS_PER_WIDE_INT);
+       result.high |= (unsigned HOST_WIDE_INT) value
+                      << (bitpos - HOST_BITS_PER_WIDE_INT);
     }
 
-  return build_int_cst_wide_type (type, lo, hi);
+  return double_int_to_tree (type, result);
 }
 
 
@@ -7541,18 +7618,16 @@ build_fold_addr_expr_with_type_loc (location_t loc, tree t, tree ptrtype)
   if (TREE_CODE (t) == WITH_SIZE_EXPR)
     t = TREE_OPERAND (t, 0);
 
-  /* Note: doesn't apply to ALIGN_INDIRECT_REF */
-  if (TREE_CODE (t) == INDIRECT_REF
-      || TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
+  if (TREE_CODE (t) == INDIRECT_REF)
     {
       t = TREE_OPERAND (t, 0);
 
       if (TREE_TYPE (t) != ptrtype)
-       {
-         t = build1 (NOP_EXPR, ptrtype, t);
-         SET_EXPR_LOCATION (t, loc);
-       }
+       t = build1_loc (loc, NOP_EXPR, ptrtype, t);
     }
+  else if (TREE_CODE (t) == MEM_REF
+      && integer_zerop (TREE_OPERAND (t, 1)))
+    return TREE_OPERAND (t, 0);
   else if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
     {
       t = build_fold_addr_expr_loc (loc, TREE_OPERAND (t, 0));
@@ -7561,10 +7636,7 @@ build_fold_addr_expr_with_type_loc (location_t loc, tree t, tree ptrtype)
        t = fold_convert_loc (loc, ptrtype, t);
     }
   else
-    {
-      t = build1 (ADDR_EXPR, ptrtype, t);
-      SET_EXPR_LOCATION (t, loc);
-    }
+    t = build1_loc (loc, ADDR_EXPR, ptrtype, t);
 
   return t;
 }
@@ -7579,6 +7651,8 @@ build_fold_addr_expr_loc (location_t loc, tree t)
   return build_fold_addr_expr_with_type_loc (loc, t, ptrtype);
 }
 
+static bool vec_cst_ctor_to_array (tree, tree *);
+
 /* Fold a unary expression of code CODE and type TYPE with operand
    OP0.  Return the folded expression if folding is successful.
    Otherwise, return NULL_TREE.  */
@@ -7597,7 +7671,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
   if (arg0)
     {
       if (CONVERT_EXPR_CODE_P (code)
-         || code == FLOAT_EXPR || code == ABS_EXPR)
+         || code == FLOAT_EXPR || code == ABS_EXPR || code == NEGATE_EXPR)
        {
          /* Don't use STRIP_NOPS, because signedness of argument type
             matters.  */
@@ -7665,33 +7739,16 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
                         (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))))
                     && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD)
                  || flag_syntax_only))
-           {
-             tem = build1 (code, type,
-                           build3 (COND_EXPR,
-                                   TREE_TYPE (TREE_OPERAND
-                                              (TREE_OPERAND (tem, 1), 0)),
-                                   TREE_OPERAND (tem, 0),
-                                   TREE_OPERAND (TREE_OPERAND (tem, 1), 0),
-                                   TREE_OPERAND (TREE_OPERAND (tem, 2), 0)));
-             SET_EXPR_LOCATION (tem, loc);
-           }
+           tem = build1_loc (loc, code, type,
+                             build3 (COND_EXPR,
+                                     TREE_TYPE (TREE_OPERAND
+                                                (TREE_OPERAND (tem, 1), 0)),
+                                     TREE_OPERAND (tem, 0),
+                                     TREE_OPERAND (TREE_OPERAND (tem, 1), 0),
+                                     TREE_OPERAND (TREE_OPERAND (tem, 2),
+                                                   0)));
          return tem;
        }
-      else if (COMPARISON_CLASS_P (arg0))
-       {
-         if (TREE_CODE (type) == BOOLEAN_TYPE)
-           {
-             arg0 = copy_node (arg0);
-             TREE_TYPE (arg0) = type;
-             return arg0;
-           }
-         else if (TREE_CODE (type) != INTEGER_TYPE)
-           return fold_build3_loc (loc, COND_EXPR, type, arg0,
-                               fold_build1_loc (loc, code, type,
-                                            integer_one_node),
-                               fold_build1_loc (loc, code, type,
-                                            integer_zero_node));
-       }
    }
 
   switch (code)
@@ -7710,11 +7767,23 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
       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_loc (loc, TREE_CODE (op0), type, TREE_OPERAND (op0, 0),
-                           TREE_OPERAND (op0, 1));
+      if (COMPARISON_CLASS_P (op0))
+       {
+         /* If we have (type) (a CMP b) and type is an integral type, return
+            new expression involving the new type.  Canonicalize
+            (type) (a CMP b) to (a CMP b) ? (type) true : (type) false for
+            non-integral type.
+            Do not fold the result as that would not simplify further, also
+            folding again results in recursions.  */
+         if (TREE_CODE (type) == BOOLEAN_TYPE)
+           return build2_loc (loc, TREE_CODE (op0), type,
+                              TREE_OPERAND (op0, 0),
+                              TREE_OPERAND (op0, 1));
+         else if (!INTEGRAL_TYPE_P (type))
+           return build3_loc (loc, COND_EXPR, type, op0,
+                              constant_boolean_node (true, type),
+                              constant_boolean_node (false, type));
+       }
 
       /* Handle cases of two conversions in a row.  */
       if (CONVERT_EXPR_P (op0))
@@ -7837,10 +7906,9 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
             unless assigning a bitfield.  */
          tem = fold_build1_loc (loc, code, type, TREE_OPERAND (op0, 1));
          /* First do the assignment, then return converted constant.  */
-         tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, tem);
+         tem = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (tem), op0, tem);
          TREE_NO_WARNING (tem) = 1;
          TREE_USED (tem) = 1;
-         SET_EXPR_LOCATION (tem, loc);
          return tem;
        }
 
@@ -7887,9 +7955,8 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
            }
          if (change)
            {
-             tem = force_fit_type_double (type, TREE_INT_CST_LOW (and1),
-                                          TREE_INT_CST_HIGH (and1), 0,
-                                          TREE_OVERFLOW (and1));
+             tem = force_fit_type_double (type, tree_to_double_int (and1),
+                                          0, TREE_OVERFLOW (and1));
              return fold_build2_loc (loc, BIT_AND_EXPR, type,
                                  fold_convert_loc (loc, type, and0), tem);
            }
@@ -7900,6 +7967,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
         that this happens when X or Y is NOP_EXPR or Y is INTEGER_CST. */
       if (POINTER_TYPE_P (type)
          && TREE_CODE (arg0) == POINTER_PLUS_EXPR
+         && (!TYPE_RESTRICT (type) || TYPE_RESTRICT (TREE_TYPE (arg0)))
          && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
              || TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
              || TREE_CODE (TREE_OPERAND (arg0, 1)) == NOP_EXPR))
@@ -7907,10 +7975,8 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
          tree arg00 = TREE_OPERAND (arg0, 0);
          tree arg01 = TREE_OPERAND (arg0, 1);
 
-         return fold_build2_loc (loc,
-                             TREE_CODE (arg0), type,
-                             fold_convert_loc (loc, type, arg00),
-                             fold_convert_loc (loc, sizetype, arg01));
+         return fold_build_pointer_plus_loc
+                  (loc, fold_convert_loc (loc, type, arg00), arg01);
        }
 
       /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types
@@ -7972,6 +8038,9 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
       if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
        return fold_build1_loc (loc, VIEW_CONVERT_EXPR,
                            type, TREE_OPERAND (op0, 0));
+      if (TREE_CODE (op0) == MEM_REF)
+       return fold_build2_loc (loc, MEM_REF, type,
+                               TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1));
 
       /* For integral conversions with the same precision or pointer
         conversions use a NOP_EXPR instead.  */
@@ -8174,7 +8243,7 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
 
     case IMAGPART_EXPR:
       if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
-       return fold_convert_loc (loc, type, integer_zero_node);
+       return build_zero_cst (type);
       if (TREE_CODE (arg0) == COMPLEX_EXPR)
        return omit_one_operand_loc (loc, type, TREE_OPERAND (arg0, 1),
                                 TREE_OPERAND (arg0, 0));
@@ -8227,6 +8296,44 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
        }
       return NULL_TREE;
 
+    case VEC_UNPACK_LO_EXPR:
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+      {
+       unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
+       tree *elts, vals = NULL_TREE;
+       enum tree_code subcode;
+
+       gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts * 2);
+       if (TREE_CODE (arg0) != VECTOR_CST)
+         return NULL_TREE;
+
+       elts = XALLOCAVEC (tree, nelts * 2);
+       if (!vec_cst_ctor_to_array (arg0, elts))
+         return NULL_TREE;
+
+       if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_UNPACK_LO_EXPR
+                                  || code == VEC_UNPACK_FLOAT_LO_EXPR))
+         elts += nelts;
+
+       if (code == VEC_UNPACK_LO_EXPR || code == VEC_UNPACK_HI_EXPR)
+         subcode = NOP_EXPR;
+       else
+         subcode = FLOAT_EXPR;
+
+       for (i = 0; i < nelts; i++)
+         {
+           elts[i] = fold_convert_const (subcode, TREE_TYPE (type), elts[i]);
+           if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i]))
+             return NULL_TREE;
+         }
+
+       for (i = 0; i < nelts; i++)
+         vals = tree_cons (NULL_TREE, elts[nelts - i - 1], vals);
+       return build_vector (type, vals);
+      }
+
     default:
       return NULL_TREE;
     } /* switch (code) */
@@ -8251,6 +8358,153 @@ fold_unary_ignore_overflow_loc (location_t loc, enum tree_code code,
   return res;
 }
 
+/* Fold a binary bitwise/truth expression of code CODE and type TYPE with
+   operands OP0 and OP1.  LOC is the location of the resulting expression.
+   ARG0 and ARG1 are the NOP_STRIPed results of OP0 and OP1.
+   Return the folded expression if folding is successful.  Otherwise,
+   return NULL_TREE.  */
+static tree
+fold_truth_andor (location_t loc, enum tree_code code, tree type,
+                 tree arg0, tree arg1, tree op0, tree op1)
+{
+  tree tem;
+
+  /* We only do these simplifications if we are optimizing.  */
+  if (!optimize)
+    return NULL_TREE;
+
+  /* Check for things like (A || B) && (A || C).  We can convert this
+     to A || (B && C).  Note that either operator can be any of the four
+     truth and/or operations and the transformation will still be
+     valid.   Also note that we only care about order for the
+     ANDIF and ORIF operators.  If B contains side effects, this
+     might change the truth-value of A.  */
+  if (TREE_CODE (arg0) == TREE_CODE (arg1)
+      && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR
+         || TREE_CODE (arg0) == TRUTH_ORIF_EXPR
+         || TREE_CODE (arg0) == TRUTH_AND_EXPR
+         || TREE_CODE (arg0) == TRUTH_OR_EXPR)
+      && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1)))
+    {
+      tree a00 = TREE_OPERAND (arg0, 0);
+      tree a01 = TREE_OPERAND (arg0, 1);
+      tree a10 = TREE_OPERAND (arg1, 0);
+      tree a11 = TREE_OPERAND (arg1, 1);
+      int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR
+                         || TREE_CODE (arg0) == TRUTH_AND_EXPR)
+                        && (code == TRUTH_AND_EXPR
+                            || code == TRUTH_OR_EXPR));
+
+      if (operand_equal_p (a00, a10, 0))
+       return fold_build2_loc (loc, TREE_CODE (arg0), type, a00,
+                           fold_build2_loc (loc, code, type, a01, a11));
+      else if (commutative && operand_equal_p (a00, a11, 0))
+       return fold_build2_loc (loc, TREE_CODE (arg0), type, a00,
+                           fold_build2_loc (loc, code, type, a01, a10));
+      else if (commutative && operand_equal_p (a01, a10, 0))
+       return fold_build2_loc (loc, TREE_CODE (arg0), type, a01,
+                           fold_build2_loc (loc, code, type, a00, a11));
+
+      /* This case if tricky because we must either have commutative
+        operators or else A10 must not have side-effects.  */
+
+      else if ((commutative || ! TREE_SIDE_EFFECTS (a10))
+              && operand_equal_p (a01, a11, 0))
+       return fold_build2_loc (loc, TREE_CODE (arg0), type,
+                           fold_build2_loc (loc, code, type, a00, a10),
+                           a01);
+    }
+
+  /* See if we can build a range comparison.  */
+  if (0 != (tem = fold_range_test (loc, code, type, op0, op1)))
+    return tem;
+
+  if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg0) == TRUTH_ORIF_EXPR)
+      || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg0) == TRUTH_ANDIF_EXPR))
+    {
+      tem = merge_truthop_with_opposite_arm (loc, arg0, arg1, true);
+      if (tem)
+       return fold_build2_loc (loc, code, type, tem, arg1);
+    }
+
+  if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg1) == TRUTH_ORIF_EXPR)
+      || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg1) == TRUTH_ANDIF_EXPR))
+    {
+      tem = merge_truthop_with_opposite_arm (loc, arg1, arg0, false);
+      if (tem)
+       return fold_build2_loc (loc, code, type, arg0, tem);
+    }
+
+  /* Check for the possibility of merging component references.  If our
+     lhs is another similar operation, try to merge its rhs with our
+     rhs.  Then try to merge our lhs and rhs.  */
+  if (TREE_CODE (arg0) == code
+      && 0 != (tem = fold_truth_andor_1 (loc, code, type,
+                                        TREE_OPERAND (arg0, 1), arg1)))
+    return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem);
+
+  if ((tem = fold_truth_andor_1 (loc, code, type, arg0, arg1)) != 0)
+    return tem;
+
+  if ((BRANCH_COST (optimize_function_for_speed_p (cfun),
+                   false) >= 2)
+      && LOGICAL_OP_NON_SHORT_CIRCUIT
+      && (code == TRUTH_AND_EXPR
+          || code == TRUTH_ANDIF_EXPR
+          || code == TRUTH_OR_EXPR
+          || code == TRUTH_ORIF_EXPR))
+    {
+      enum tree_code ncode, icode;
+
+      ncode = (code == TRUTH_ANDIF_EXPR || code == TRUTH_AND_EXPR)
+             ? TRUTH_AND_EXPR : TRUTH_OR_EXPR;
+      icode = ncode == TRUTH_AND_EXPR ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+
+      /* Transform ((A AND-IF B) AND[-IF] C) into (A AND-IF (B AND C)),
+        or ((A OR-IF B) OR[-IF] C) into (A OR-IF (B OR C))
+        We don't want to pack more than two leafs to a non-IF AND/OR
+        expression.
+        If tree-code of left-hand operand isn't an AND/OR-IF code and not
+        equal to IF-CODE, then we don't want to add right-hand operand.
+        If the inner right-hand side of left-hand operand has
+        side-effects, or isn't simple, then we can't add to it,
+        as otherwise we might destroy if-sequence.  */
+      if (TREE_CODE (arg0) == icode
+         && simple_operand_p_2 (arg1)
+         /* Needed for sequence points to handle trappings, and
+            side-effects.  */
+         && simple_operand_p_2 (TREE_OPERAND (arg0, 1)))
+       {
+         tem = fold_build2_loc (loc, ncode, type, TREE_OPERAND (arg0, 1),
+                                arg1);
+         return fold_build2_loc (loc, icode, type, TREE_OPERAND (arg0, 0),
+                                 tem);
+       }
+       /* Same as abouve but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
+          or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C).  */
+      else if (TREE_CODE (arg1) == icode
+         && simple_operand_p_2 (arg0)
+         /* Needed for sequence points to handle trappings, and
+            side-effects.  */
+         && simple_operand_p_2 (TREE_OPERAND (arg1, 0)))
+       {
+         tem = fold_build2_loc (loc, ncode, type, 
+                                arg0, TREE_OPERAND (arg1, 0));
+         return fold_build2_loc (loc, icode, type, tem,
+                                 TREE_OPERAND (arg1, 1));
+       }
+      /* Transform (A AND-IF B) into (A AND B), or (A OR-IF B)
+        into (A OR B).
+        For sequence point consistancy, we need to check for trapping,
+        and side-effects.  */
+      else if (code == icode && simple_operand_p_2 (arg0)
+               && simple_operand_p_2 (arg1))
+       return fold_build2_loc (loc, ncode, type, arg0, arg1);
+    }
+
+  return NULL_TREE;
+}
+
 /* Fold a binary expression of code CODE and type TYPE with operands
    OP0 and OP1, containing either a MIN-MAX or a MAX-MIN combination.
    Return the folded expression if folding is successful.  Otherwise,
@@ -8394,9 +8648,10 @@ maybe_canonicalize_comparison_1 (location_t loc, enum tree_code code, tree type,
     return NULL_TREE;
 
   t = int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR,
-                      cst0, build_int_cst (TREE_TYPE (cst0), 1), 0);
+                      cst0, build_int_cst (TREE_TYPE (cst0), 1));
   if (code0 != INTEGER_CST)
     t = fold_build2_loc (loc, code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t);
+  t = fold_convert (TREE_TYPE (arg1), t);
 
   /* If swapping might yield to a more canonical form, do so.  */
   if (swap)
@@ -8581,10 +8836,11 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
          && (TREE_CODE (lhs) != INTEGER_CST
              || !TREE_OVERFLOW (lhs)))
        {
-         fold_overflow_warning (("assuming signed overflow does not occur "
-                                 "when changing X +- C1 cmp C2 to "
-                                 "X cmp C1 +- C2"),
-                                WARN_STRICT_OVERFLOW_COMPARISON);
+         if (code != EQ_EXPR && code != NE_EXPR)
+           fold_overflow_warning ("assuming signed overflow does not occur "
+                                  "when changing X +- C1 cmp C2 to "
+                                  "X cmp C1 +- C2",
+                                  WARN_STRICT_OVERFLOW_COMPARISON);
          return fold_build2_loc (loc, code, type, variable, lhs);
        }
     }
@@ -8623,7 +8879,24 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
       else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
        {
          base0 = TREE_OPERAND (arg0, 0);
+         STRIP_SIGN_NOPS (base0);
+         if (TREE_CODE (base0) == ADDR_EXPR)
+           {
+             base0 = TREE_OPERAND (base0, 0);
+             indirect_base0 = true;
+           }
          offset0 = TREE_OPERAND (arg0, 1);
+         if (host_integerp (offset0, 0))
+           {
+             HOST_WIDE_INT off = size_low_cst (offset0);
+             if ((HOST_WIDE_INT) (((unsigned HOST_WIDE_INT) off)
+                                  * BITS_PER_UNIT)
+                 / BITS_PER_UNIT == (HOST_WIDE_INT) off)
+               {
+                 bitpos0 = off * BITS_PER_UNIT;
+                 offset0 = NULL_TREE;
+               }
+           }
        }
 
       base1 = arg1;
@@ -8640,7 +8913,24 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
       else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR)
        {
          base1 = TREE_OPERAND (arg1, 0);
+         STRIP_SIGN_NOPS (base1);
+         if (TREE_CODE (base1) == ADDR_EXPR)
+           {
+             base1 = TREE_OPERAND (base1, 0);
+             indirect_base1 = true;
+           }
          offset1 = TREE_OPERAND (arg1, 1);
+         if (host_integerp (offset1, 0))
+           {
+             HOST_WIDE_INT off = size_low_cst (offset1);
+             if ((HOST_WIDE_INT) (((unsigned HOST_WIDE_INT) off)
+                                  * BITS_PER_UNIT)
+                 / BITS_PER_UNIT == (HOST_WIDE_INT) off)
+               {
+                 bitpos1 = off * BITS_PER_UNIT;
+                 offset1 = NULL_TREE;
+               }
+           }
        }
 
       /* A local variable can never be pointed to by
@@ -8678,6 +8968,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
                   && operand_equal_p (offset0, offset1, 0)))
              && (code == EQ_EXPR
                  || code == NE_EXPR
+                 || (indirect_base0 && DECL_P (base0))
                  || POINTER_TYPE_OVERFLOW_UNDEFINED))
 
            {
@@ -8717,6 +9008,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
             6.5.6/8 and /9 with respect to the signed ptrdiff_t.  */
          else if (bitpos0 == bitpos1
                   && ((code == EQ_EXPR || code == NE_EXPR)
+                      || (indirect_base0 && DECL_P (base0))
                       || POINTER_TYPE_OVERFLOW_UNDEFINED))
            {
              /* By converting to signed size type we cover middle-end pointer
@@ -8816,7 +9108,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
         of lower absolute value than before.  */
       cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
                             ? MINUS_EXPR : PLUS_EXPR,
-                            const2, const1, 0);
+                            const2, const1);
       if (!TREE_OVERFLOW (cst)
          && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2))
        {
@@ -8830,7 +9122,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
 
       cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
                             ? MINUS_EXPR : PLUS_EXPR,
-                            const1, const2, 0);
+                            const1, const2);
       if (!TREE_OVERFLOW (cst)
          && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1))
        {
@@ -8873,7 +9165,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
       return fold_build2_loc (loc, cmp_code, type, variable1, const2);
     }
 
-  tem = maybe_canonicalize_comparison (loc, code, type, op0, op1);
+  tem = maybe_canonicalize_comparison (loc, code, type, arg0, arg1);
   if (tem)
     return tem;
 
@@ -8908,7 +9200,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
            return fold_build2_loc (loc, swap_tree_comparison (code), type,
                                TREE_OPERAND (arg0, 0),
                                build_real (TREE_TYPE (arg1),
-                                           REAL_VALUE_NEGATE (cst)));
+                                           real_value_negate (&cst)));
 
          /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
          /* a CMP (-0) -> a CMP 0  */
@@ -8945,7 +9237,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
          && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
                                      ? MINUS_EXPR : PLUS_EXPR,
-                                     arg1, TREE_OPERAND (arg0, 1), 0))
+                                     arg1, TREE_OPERAND (arg0, 1)))
          && !TREE_OVERFLOW (tem))
        return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem);
 
@@ -8958,7 +9250,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
          && TREE_CODE (arg0) == MINUS_EXPR
          && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
          && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
-                                     arg1, 0))
+                                     arg1))
          && !TREE_OVERFLOW (tem))
        return fold_build2_loc (loc, swap_tree_comparison (code), type,
                            TREE_OPERAND (arg0, 1), tem);
@@ -9217,7 +9509,7 @@ fold_mult_zconjz (location_t loc, tree type, tree expr)
                     fold_build2_loc (loc, MULT_EXPR, itype, rpart, rpart),
                     fold_build2_loc (loc, MULT_EXPR, itype, ipart, ipart));
   return fold_build2_loc (loc, COMPLEX_EXPR, type, tem,
-                     fold_convert_loc (loc, itype, integer_zero_node));
+                         build_zero_cst (itype));
 }
 
 
@@ -9245,30 +9537,10 @@ get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue,
   code = TREE_CODE (expr);
   if (code == ADDR_EXPR)
     {
-      expr = TREE_OPERAND (expr, 0);
-      if (handled_component_p (expr))
-       {
-         HOST_WIDE_INT bitsize, bitpos;
-         tree offset;
-         enum machine_mode mode;
-         int unsignedp, volatilep;
-
-         expr = get_inner_reference (expr, &bitsize, &bitpos, &offset,
-                                     &mode, &unsignedp, &volatilep, false);
-         *residue = bitpos / BITS_PER_UNIT;
-         if (offset)
-           {
-             if (TREE_CODE (offset) == INTEGER_CST)
-               *residue += TREE_INT_CST_LOW (offset);
-             else
-               /* We don't handle more complicated offset expressions.  */
-               return 1;
-           }
-       }
-
-      if (DECL_P (expr)
-         && (allow_func_align || TREE_CODE (expr) != FUNCTION_DECL))
-       return DECL_ALIGN_UNIT (expr);
+      unsigned int bitalign;
+      bitalign = get_object_alignment_1 (TREE_OPERAND (expr, 0), residue);
+      *residue /= BITS_PER_UNIT;
+      return bitalign / BITS_PER_UNIT;
     }
   else if (code == POINTER_PLUS_EXPR)
     {
@@ -9313,11 +9585,91 @@ get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue,
        }
     }
 
-    /* If we get here, we were unable to determine anything useful about the
-       expression.  */
-    return 1;
+  /* If we get here, we were unable to determine anything useful about the
+     expression.  */
+  return 1;
+}
+
+/* Helper function for fold_vec_perm.  Store elements of VECTOR_CST or
+   CONSTRUCTOR ARG into array ELTS and return true if successful.  */
+
+static bool
+vec_cst_ctor_to_array (tree arg, tree *elts)
+{
+  unsigned int nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg)), i;
+
+  if (TREE_CODE (arg) == VECTOR_CST)
+    {
+      tree t;
+
+      for (i = 0, t = TREE_VECTOR_CST_ELTS (arg);
+          i < nelts && t; i++, t = TREE_CHAIN (t))
+       elts[i] = TREE_VALUE (t);
+      if (t)
+       return false;
+    }
+  else if (TREE_CODE (arg) == CONSTRUCTOR)
+    {
+      constructor_elt *elt;
+
+      FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (arg), i, elt)
+       if (i >= nelts)
+         return false;
+       else
+         elts[i] = elt->value;
+    }
+  else
+    return false;
+  for (; i < nelts; i++)
+    elts[i]
+      = fold_convert (TREE_TYPE (TREE_TYPE (arg)), integer_zero_node);
+  return true;
 }
 
+/* Attempt to fold vector permutation of ARG0 and ARG1 vectors using SEL
+   selector.  Return the folded VECTOR_CST or CONSTRUCTOR if successful,
+   NULL_TREE otherwise.  */
+
+static tree
+fold_vec_perm (tree type, tree arg0, tree arg1, const unsigned char *sel)
+{
+  unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
+  tree *elts;
+  bool need_ctor = false;
+
+  gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts
+             && TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)) == nelts);
+  if (TREE_TYPE (TREE_TYPE (arg0)) != TREE_TYPE (type)
+      || TREE_TYPE (TREE_TYPE (arg1)) != TREE_TYPE (type))
+    return NULL_TREE;
+
+  elts = XALLOCAVEC (tree, nelts * 3);
+  if (!vec_cst_ctor_to_array (arg0, elts)
+      || !vec_cst_ctor_to_array (arg1, elts + nelts))
+    return NULL_TREE;
+
+  for (i = 0; i < nelts; i++)
+    {
+      if (!CONSTANT_CLASS_P (elts[sel[i]]))
+       need_ctor = true;
+      elts[i + 2 * nelts] = unshare_expr (elts[sel[i]]);
+    }
+
+  if (need_ctor)
+    {
+      VEC(constructor_elt,gc) *v = VEC_alloc (constructor_elt, gc, nelts);
+      for (i = 0; i < nelts; i++)
+       CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elts[2 * nelts + i]);
+      return build_constructor (type, v);
+    }
+  else
+    {
+      tree vals = NULL_TREE;
+      for (i = 0; i < nelts; i++)
+       vals = tree_cons (NULL_TREE, elts[3 * nelts - i - 1], vals);
+      return build_vector (type, vals);
+    }
+}
 
 /* Fold a binary expression of code CODE and type TYPE with operands
    OP0 and OP1.  LOC is the location of the resulting expression.
@@ -9379,7 +9731,7 @@ fold_binary_loc (location_t loc,
          /* Make sure type and arg0 have the same saturating flag.  */
          gcc_assert (TYPE_SATURATING (type)
                      == TYPE_SATURATING (TREE_TYPE (arg0)));
-         tem = const_binop (code, arg0, arg1, 0);
+         tem = const_binop (code, arg0, arg1);
        }
       else if (kind == tcc_comparison)
        tem = fold_relational_const (code, type, arg0, arg1);
@@ -9448,8 +9800,8 @@ fold_binary_loc (location_t loc,
          tem = fold_build2_loc (loc, code, type,
                             fold_convert_loc (loc, TREE_TYPE (op0),
                                               TREE_OPERAND (arg0, 1)), op1);
-         tem = build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), tem);
-         goto fold_binary_exit;
+         return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                            tem);
        }
       if (TREE_CODE (arg1) == COMPOUND_EXPR
          && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
@@ -9457,8 +9809,8 @@ fold_binary_loc (location_t loc,
          tem = fold_build2_loc (loc, code, type, op0,
                             fold_convert_loc (loc, TREE_TYPE (op1),
                                               TREE_OPERAND (arg1, 1)));
-         tem = build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0), tem);
-         goto fold_binary_exit;
+         return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+                            tem);
        }
 
       if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
@@ -9482,6 +9834,36 @@ fold_binary_loc (location_t loc,
 
   switch (code)
     {
+    case MEM_REF:
+      /* MEM[&MEM[p, CST1], CST2] -> MEM[p, CST1 + CST2].  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == MEM_REF)
+       {
+         tree iref = TREE_OPERAND (arg0, 0);
+         return fold_build2 (MEM_REF, type,
+                             TREE_OPERAND (iref, 0),
+                             int_const_binop (PLUS_EXPR, arg1,
+                                              TREE_OPERAND (iref, 1)));
+       }
+
+      /* MEM[&a.b, CST2] -> MEM[&a, offsetof (a, b) + CST2].  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+         && handled_component_p (TREE_OPERAND (arg0, 0)))
+       {
+         tree base;
+         HOST_WIDE_INT coffset;
+         base = get_addr_base_and_unit_offset (TREE_OPERAND (arg0, 0),
+                                               &coffset);
+         if (!base)
+           return NULL_TREE;
+         return fold_build2 (MEM_REF, type,
+                             build_fold_addr_expr (base),
+                             int_const_binop (PLUS_EXPR, arg1,
+                                              size_int (coffset)));
+       }
+
+      return NULL_TREE;
+
     case POINTER_PLUS_EXPR:
       /* 0 +p index -> (type)index */
       if (integer_zerop (arg0))
@@ -9501,13 +9883,6 @@ fold_binary_loc (location_t loc,
                                              fold_convert_loc (loc, sizetype,
                                                                arg0)));
 
-      /* index +p PTR -> PTR +p index */
-      if (POINTER_TYPE_P (TREE_TYPE (arg1))
-         && INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
-        return fold_build2_loc (loc, POINTER_PLUS_EXPR, type,
-                           fold_convert_loc (loc, type, arg1),
-                           fold_convert_loc (loc, sizetype, arg0));
-
       /* (PTR +p B) +p A -> PTR +p (B + A) */
       if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
        {
@@ -9517,9 +9892,8 @@ fold_binary_loc (location_t loc,
          inner = fold_build2_loc (loc, PLUS_EXPR, sizetype,
                               arg01, fold_convert_loc (loc, sizetype, arg1));
          return fold_convert_loc (loc, type,
-                                  fold_build2_loc (loc, POINTER_PLUS_EXPR,
-                                               TREE_TYPE (arg00),
-                                               arg00, inner));
+                                  fold_build_pointer_plus_loc (loc,
+                                                               arg00, inner));
        }
 
       /* PTR_CST +p CST -> CST1 */
@@ -9638,7 +10012,7 @@ fold_binary_loc (location_t loc,
              && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
              && integer_zerop (const_binop (BIT_AND_EXPR,
                                             TREE_OPERAND (arg0, 1),
-                                            TREE_OPERAND (arg1, 1), 0)))
+                                            TREE_OPERAND (arg1, 1))))
            {
              code = BIT_IOR_EXPR;
              goto bit_ior;
@@ -9647,12 +10021,13 @@ fold_binary_loc (location_t loc,
          /* Reassociate (plus (plus (mult) (foo)) (mult)) as
             (plus (plus (mult) (mult)) (foo)) so that we can
             take advantage of the factoring cases below.  */
-         if (((TREE_CODE (arg0) == PLUS_EXPR
-               || TREE_CODE (arg0) == MINUS_EXPR)
-              && TREE_CODE (arg1) == MULT_EXPR)
-             || ((TREE_CODE (arg1) == PLUS_EXPR
-                  || TREE_CODE (arg1) == MINUS_EXPR)
-                 && TREE_CODE (arg0) == MULT_EXPR))
+         if (TYPE_OVERFLOW_WRAPS (type)
+             && (((TREE_CODE (arg0) == PLUS_EXPR
+                   || TREE_CODE (arg0) == MINUS_EXPR)
+                  && TREE_CODE (arg1) == MULT_EXPR)
+                 || ((TREE_CODE (arg1) == PLUS_EXPR
+                      || TREE_CODE (arg1) == MINUS_EXPR)
+                     && TREE_CODE (arg0) == MULT_EXPR)))
            {
              tree parg0, parg1, parg, marg;
              enum tree_code pcode;
@@ -9827,12 +10202,10 @@ fold_binary_loc (location_t loc,
                && ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
                    == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
              {
-               tem = build2 (LROTATE_EXPR,
-                             TREE_TYPE (TREE_OPERAND (arg0, 0)),
-                             TREE_OPERAND (arg0, 0),
-                             code0 == LSHIFT_EXPR
-                             ? tree01 : tree11);
-               SET_EXPR_LOCATION (tem, loc);
+               tem = build2_loc (loc, LROTATE_EXPR,
+                                 TREE_TYPE (TREE_OPERAND (arg0, 0)),
+                                 TREE_OPERAND (arg0, 0),
+                                 code0 == LSHIFT_EXPR ? tree01 : tree11);
                return fold_convert_loc (loc, type, tem);
              }
            else if (code11 == MINUS_EXPR)
@@ -10179,7 +10552,7 @@ fold_binary_loc (location_t loc,
 
       if ((!FLOAT_TYPE_P (type) || !HONOR_NANS (TYPE_MODE (type)))
          && operand_equal_p (arg0, arg1, 0))
-       return fold_convert_loc (loc, type, integer_zero_node);
+       return build_zero_cst (type);
 
       /* A - B -> A + (-B) if B is easily negatable.  */
       if (negate_expr_p (arg1)
@@ -10360,7 +10733,7 @@ fold_binary_loc (location_t loc,
              && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST)
            {
              tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0),
-                                     arg1, 0);
+                                     arg1);
              if (tem)
                return fold_build2_loc (loc, RDIV_EXPR, type, tem,
                                    TREE_OPERAND (arg0, 1));
@@ -10537,8 +10910,9 @@ fold_binary_loc (location_t loc,
                    }
                }
 
-             /* Optimize x*x as pow(x,2.0), which is expanded as x*x.  */
-             if (optimize_function_for_speed_p (cfun)
+             /* Canonicalize x*x as pow(x,2.0), which is expanded as x*x.  */
+             if (!in_gimple_form
+                 && optimize
                  && operand_equal_p (arg0, arg1, 0))
                {
                  tree powfn = mathfn_built_in (type, BUILT_IN_POW);
@@ -10566,7 +10940,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg0) == BIT_NOT_EXPR
          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg1);
        }
@@ -10575,7 +10949,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg1) == BIT_NOT_EXPR
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg0);
        }
@@ -10667,6 +11041,28 @@ fold_binary_loc (location_t loc,
          && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
        return omit_one_operand_loc (loc, type, arg0, TREE_OPERAND (arg1, 0));
 
+      /* (X & ~Y) | (~X & Y) is X ^ Y */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && TREE_CODE (arg1) == BIT_AND_EXPR)
+        {
+         tree a0, a1, l0, l1, n0, n1;
+
+         a0 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0));
+         a1 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1));
+
+         l0 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
+         l1 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
+         
+         n0 = fold_build1_loc (loc, BIT_NOT_EXPR, type, l0);
+         n1 = fold_build1_loc (loc, BIT_NOT_EXPR, type, l1);
+         
+         if ((operand_equal_p (n0, a0, 0)
+              && operand_equal_p (n1, a1, 0))
+             || (operand_equal_p (n0, a1, 0)
+                 && operand_equal_p (n1, a0, 0)))
+           return fold_build2_loc (loc, BIT_XOR_EXPR, type, l0, n1);
+       }
+
       t1 = distribute_bit_expr (loc, code, type, arg0, arg1);
       if (t1 != NULL_TREE)
        return t1;
@@ -10705,7 +11101,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg0) == BIT_NOT_EXPR
          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg1);
        }
@@ -10714,7 +11110,7 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg1) == BIT_NOT_EXPR
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        {
-         t1 = fold_convert_loc (loc, type, integer_zero_node);
+         t1 = build_zero_cst (type);
          t1 = fold_unary_loc (loc, BIT_NOT_EXPR, type, t1);
          return omit_one_operand_loc (loc, type, t1, arg0);
        }
@@ -10729,7 +11125,7 @@ fold_binary_loc (location_t loc,
          && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
          && integer_zerop (const_binop (BIT_AND_EXPR,
                                         TREE_OPERAND (arg0, 1),
-                                        TREE_OPERAND (arg1, 1), 0)))
+                                        TREE_OPERAND (arg1, 1))))
        {
          code = BIT_IOR_EXPR;
          goto bit_ior;
@@ -10862,13 +11258,19 @@ fold_binary_loc (location_t loc,
       if (operand_equal_p (arg0, arg1, 0))
        return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0));
 
-      /* ~X & X is always zero.  */
-      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+      /* ~X & X, (X == 0) & X, and !X & X are always zero.  */
+      if ((TREE_CODE (arg0) == BIT_NOT_EXPR
+          || TREE_CODE (arg0) == TRUTH_NOT_EXPR
+          || (TREE_CODE (arg0) == EQ_EXPR
+              && integer_zerop (TREE_OPERAND (arg0, 1))))
          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
        return omit_one_operand_loc (loc, type, integer_zero_node, arg1);
 
-      /* X & ~X is always zero.  */
-      if (TREE_CODE (arg1) == BIT_NOT_EXPR
+      /* X & ~X , X & (X == 0), and X & !X are always zero.  */
+      if ((TREE_CODE (arg1) == BIT_NOT_EXPR
+          || TREE_CODE (arg1) == TRUTH_NOT_EXPR
+          || (TREE_CODE (arg1) == EQ_EXPR
+              && integer_zerop (TREE_OPERAND (arg1, 1))))
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
 
@@ -10929,6 +11331,14 @@ fold_binary_loc (location_t loc,
                                           build_int_cst (TREE_TYPE (tem), 1)),
                              build_int_cst (TREE_TYPE (tem), 0));
        }
+      /* Fold !X & 1 as X == 0.  */
+      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
+         && integer_onep (arg1))
+       {
+         tem = TREE_OPERAND (arg0, 0);
+         return fold_build2_loc (loc, EQ_EXPR, type, tem,
+                                 build_int_cst (TREE_TYPE (tem), 0));
+       }
 
       /* Fold (X ^ Y) & Y as ~X & Y.  */
       if (TREE_CODE (arg0) == BIT_XOR_EXPR
@@ -10969,6 +11379,126 @@ fold_binary_loc (location_t loc,
                              fold_convert_loc (loc, type, arg0));
        }
 
+      /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
+        ((A & N) + B) & M -> (A + B) & M
+        Similarly if (N & M) == 0,
+        ((A | N) + B) & M -> (A + B) & M
+        and for - instead of + (or unary - instead of +)
+        and/or ^ instead of |.
+        If B is constant and (B & M) == 0, fold into A & M.  */
+      if (host_integerp (arg1, 1))
+       {
+         unsigned HOST_WIDE_INT cst1 = tree_low_cst (arg1, 1);
+         if (~cst1 && (cst1 & (cst1 + 1)) == 0
+             && INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+             && (TREE_CODE (arg0) == PLUS_EXPR
+                 || TREE_CODE (arg0) == MINUS_EXPR
+                 || TREE_CODE (arg0) == NEGATE_EXPR)
+             && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
+                 || TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE))
+           {
+             tree pmop[2];
+             int which = 0;
+             unsigned HOST_WIDE_INT cst0;
+
+             /* Now we know that arg0 is (C + D) or (C - D) or
+                -C and arg1 (M) is == (1LL << cst) - 1.
+                Store C into PMOP[0] and D into PMOP[1].  */
+             pmop[0] = TREE_OPERAND (arg0, 0);
+             pmop[1] = NULL;
+             if (TREE_CODE (arg0) != NEGATE_EXPR)
+               {
+                 pmop[1] = TREE_OPERAND (arg0, 1);
+                 which = 1;
+               }
+
+             if (!host_integerp (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+                 || (tree_low_cst (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+                     & cst1) != cst1)
+               which = -1;
+
+             for (; which >= 0; which--)
+               switch (TREE_CODE (pmop[which]))
+                 {
+                 case BIT_AND_EXPR:
+                 case BIT_IOR_EXPR:
+                 case BIT_XOR_EXPR:
+                   if (TREE_CODE (TREE_OPERAND (pmop[which], 1))
+                       != INTEGER_CST)
+                     break;
+                   /* tree_low_cst not used, because we don't care about
+                      the upper bits.  */
+                   cst0 = TREE_INT_CST_LOW (TREE_OPERAND (pmop[which], 1));
+                   cst0 &= cst1;
+                   if (TREE_CODE (pmop[which]) == BIT_AND_EXPR)
+                     {
+                       if (cst0 != cst1)
+                         break;
+                     }
+                   else if (cst0 != 0)
+                     break;
+                   /* If C or D is of the form (A & N) where
+                      (N & M) == M, or of the form (A | N) or
+                      (A ^ N) where (N & M) == 0, replace it with A.  */
+                   pmop[which] = TREE_OPERAND (pmop[which], 0);
+                   break;
+                 case INTEGER_CST:
+                   /* If C or D is a N where (N & M) == 0, it can be
+                      omitted (assumed 0).  */
+                   if ((TREE_CODE (arg0) == PLUS_EXPR
+                        || (TREE_CODE (arg0) == MINUS_EXPR && which == 0))
+                       && (TREE_INT_CST_LOW (pmop[which]) & cst1) == 0)
+                     pmop[which] = NULL;
+                   break;
+                 default:
+                   break;
+                 }
+
+             /* Only build anything new if we optimized one or both arguments
+                above.  */
+             if (pmop[0] != TREE_OPERAND (arg0, 0)
+                 || (TREE_CODE (arg0) != NEGATE_EXPR
+                     && pmop[1] != TREE_OPERAND (arg0, 1)))
+               {
+                 tree utype = TREE_TYPE (arg0);
+                 if (! TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
+                   {
+                     /* Perform the operations in a type that has defined
+                        overflow behavior.  */
+                     utype = unsigned_type_for (TREE_TYPE (arg0));
+                     if (pmop[0] != NULL)
+                       pmop[0] = fold_convert_loc (loc, utype, pmop[0]);
+                     if (pmop[1] != NULL)
+                       pmop[1] = fold_convert_loc (loc, utype, pmop[1]);
+                   }
+
+                 if (TREE_CODE (arg0) == NEGATE_EXPR)
+                   tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[0]);
+                 else if (TREE_CODE (arg0) == PLUS_EXPR)
+                   {
+                     if (pmop[0] != NULL && pmop[1] != NULL)
+                       tem = fold_build2_loc (loc, PLUS_EXPR, utype,
+                                              pmop[0], pmop[1]);
+                     else if (pmop[0] != NULL)
+                       tem = pmop[0];
+                     else if (pmop[1] != NULL)
+                       tem = pmop[1];
+                     else
+                       return build_int_cst (type, 0);
+                   }
+                 else if (pmop[0] == NULL)
+                   tem = fold_build1_loc (loc, NEGATE_EXPR, utype, pmop[1]);
+                 else
+                   tem = fold_build2_loc (loc, MINUS_EXPR, utype,
+                                          pmop[0], pmop[1]);
+                 /* TEM is now the new binary +, - or unary - replacement.  */
+                 tem = fold_build2_loc (loc, BIT_AND_EXPR, utype, tem,
+                                        fold_convert_loc (loc, utype, arg1));
+                 return fold_convert_loc (loc, type, tem);
+               }
+           }
+       }
+
       t1 = distribute_bit_expr (loc, code, type, arg0, arg1);
       if (t1 != NULL_TREE)
        return t1;
@@ -11185,7 +11715,7 @@ fold_binary_loc (location_t loc,
        {
          if (flag_reciprocal_math
              && 0 != (tem = const_binop (code, build_real (type, dconst1),
-                                         arg1, 0)))
+                                         arg1)))
            return fold_build2_loc (loc, MULT_EXPR, type, arg0, tem);
          /* Find the reciprocal if optimizing and the result is exact.  */
          if (optimize)
@@ -11222,7 +11752,7 @@ fold_binary_loc (location_t loc,
          && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
        {
          tree tem = const_binop (RDIV_EXPR, arg0,
-                                 TREE_OPERAND (arg1, 1), 0);
+                                 TREE_OPERAND (arg1, 1));
          if (tem)
            return fold_build2_loc (loc, RDIV_EXPR, type, tem,
                                TREE_OPERAND (arg1, 0));
@@ -11377,6 +11907,31 @@ fold_binary_loc (location_t loc,
       return NULL_TREE;
 
     case TRUNC_DIV_EXPR:
+      /* Optimize (X & (-A)) / A where A is a power of 2,
+        to X >> log2(A) */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && !TYPE_UNSIGNED (type) && TREE_CODE (arg1) == INTEGER_CST
+         && integer_pow2p (arg1) && tree_int_cst_sgn (arg1) > 0)
+       {
+         tree sum = fold_binary_loc (loc, PLUS_EXPR, TREE_TYPE (arg1),
+                                     arg1, TREE_OPERAND (arg0, 1));
+         if (sum && integer_zerop (sum)) {
+           unsigned long pow2;
+
+           if (TREE_INT_CST_LOW (arg1))
+             pow2 = exact_log2 (TREE_INT_CST_LOW (arg1));
+           else
+             pow2 = exact_log2 (TREE_INT_CST_HIGH (arg1))
+                     + HOST_BITS_PER_WIDE_INT;
+
+           return fold_build2_loc (loc, RSHIFT_EXPR, type,
+                         TREE_OPERAND (arg0, 0),
+                         build_int_cst (integer_type_node, pow2));
+         }
+       }
+
+      /* Fall thru */
+      
     case FLOOR_DIV_EXPR:
       /* Simplify A / (B << N) where A and B are positive and B is
         a power of 2, to A >> (N + log2(B)).  */
@@ -11389,7 +11944,13 @@ fold_binary_loc (location_t loc,
          if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0)
            {
              tree sh_cnt = TREE_OPERAND (arg1, 1);
-             unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval));
+             unsigned long pow2;
+
+             if (TREE_INT_CST_LOW (sval))
+               pow2 = exact_log2 (TREE_INT_CST_LOW (sval));
+             else
+               pow2 = exact_log2 (TREE_INT_CST_HIGH (sval))
+                      + HOST_BITS_PER_WIDE_INT;
 
              if (strict_overflow_p)
                fold_overflow_warning (("assuming signed overflow does not "
@@ -11397,7 +11958,9 @@ fold_binary_loc (location_t loc,
                                       WARN_STRICT_OVERFLOW_MISC);
 
              sh_cnt = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (sh_cnt),
-                                   sh_cnt, build_int_cst (NULL_TREE, pow2));
+                                       sh_cnt,
+                                       build_int_cst (TREE_TYPE (sh_cnt),
+                                                      pow2));
              return fold_build2_loc (loc, RSHIFT_EXPR, type,
                                  fold_convert_loc (loc, type, arg0), sh_cnt);
            }
@@ -11645,7 +12208,7 @@ fold_binary_loc (location_t loc,
              arg00 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
 
              lshift = build_int_cst (type, -1);
-             lshift = int_const_binop (code, lshift, arg1, 0);
+             lshift = int_const_binop (code, lshift, arg1);
 
              return fold_build2_loc (loc, BIT_AND_EXPR, type, arg00, lshift);
            }
@@ -11657,7 +12220,7 @@ fold_binary_loc (location_t loc,
        {
          tree tem = build_int_cst (TREE_TYPE (arg1),
                                    TYPE_PRECISION (type));
-         tem = const_binop (MINUS_EXPR, tem, arg1, 0);
+         tem = const_binop (MINUS_EXPR, tem, arg1);
          return fold_build2_loc (loc, RROTATE_EXPR, type, op0, tem);
        }
 
@@ -11782,67 +12345,9 @@ fold_binary_loc (location_t loc,
            return fold_build2_loc (loc, code, type, arg0, tem);
        }
 
-    truth_andor:
-      /* We only do these simplifications if we are optimizing.  */
-      if (!optimize)
-       return NULL_TREE;
-
-      /* Check for things like (A || B) && (A || C).  We can convert this
-        to A || (B && C).  Note that either operator can be any of the four
-        truth and/or operations and the transformation will still be
-        valid.   Also note that we only care about order for the
-        ANDIF and ORIF operators.  If B contains side effects, this
-        might change the truth-value of A.  */
-      if (TREE_CODE (arg0) == TREE_CODE (arg1)
-         && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR
-             || TREE_CODE (arg0) == TRUTH_ORIF_EXPR
-             || TREE_CODE (arg0) == TRUTH_AND_EXPR
-             || TREE_CODE (arg0) == TRUTH_OR_EXPR)
-         && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1)))
-       {
-         tree a00 = TREE_OPERAND (arg0, 0);
-         tree a01 = TREE_OPERAND (arg0, 1);
-         tree a10 = TREE_OPERAND (arg1, 0);
-         tree a11 = TREE_OPERAND (arg1, 1);
-         int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR
-                             || TREE_CODE (arg0) == TRUTH_AND_EXPR)
-                            && (code == TRUTH_AND_EXPR
-                                || code == TRUTH_OR_EXPR));
-
-         if (operand_equal_p (a00, a10, 0))
-           return fold_build2_loc (loc, TREE_CODE (arg0), type, a00,
-                               fold_build2_loc (loc, code, type, a01, a11));
-         else if (commutative && operand_equal_p (a00, a11, 0))
-           return fold_build2_loc (loc, TREE_CODE (arg0), type, a00,
-                               fold_build2_loc (loc, code, type, a01, a10));
-         else if (commutative && operand_equal_p (a01, a10, 0))
-           return fold_build2_loc (loc, TREE_CODE (arg0), type, a01,
-                               fold_build2_loc (loc, code, type, a00, a11));
-
-         /* This case if tricky because we must either have commutative
-            operators or else A10 must not have side-effects.  */
-
-         else if ((commutative || ! TREE_SIDE_EFFECTS (a10))
-                  && operand_equal_p (a01, a11, 0))
-           return fold_build2_loc (loc, TREE_CODE (arg0), type,
-                               fold_build2_loc (loc, code, type, a00, a10),
-                               a01);
-       }
-
-      /* See if we can build a range comparison.  */
-      if (0 != (tem = fold_range_test (loc, code, type, op0, op1)))
-       return tem;
-
-      /* Check for the possibility of merging component references.  If our
-        lhs is another similar operation, try to merge its rhs with our
-        rhs.  Then try to merge our lhs and rhs.  */
-      if (TREE_CODE (arg0) == code
-         && 0 != (tem = fold_truthop (loc, code, type,
-                                      TREE_OPERAND (arg0, 1), arg1)))
-       return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem);
-
-      if ((tem = fold_truthop (loc, code, type, arg0, arg1)) != 0)
-       return tem;
+      if ((tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1))
+          != NULL_TREE)
+        return tem;
 
       return NULL_TREE;
 
@@ -11879,7 +12384,33 @@ fold_binary_loc (location_t loc,
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        return omit_one_operand_loc (loc, type, integer_one_node, arg0);
 
-      goto truth_andor;
+      /* (X && !Y) || (!X && Y) is X ^ Y */
+      if (TREE_CODE (arg0) == TRUTH_AND_EXPR
+         && TREE_CODE (arg1) == TRUTH_AND_EXPR)
+        {
+         tree a0, a1, l0, l1, n0, n1;
+
+         a0 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 0));
+         a1 = fold_convert_loc (loc, type, TREE_OPERAND (arg1, 1));
+
+         l0 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
+         l1 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
+         
+         n0 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l0);
+         n1 = fold_build1_loc (loc, TRUTH_NOT_EXPR, type, l1);
+         
+         if ((operand_equal_p (n0, a0, 0)
+              && operand_equal_p (n1, a1, 0))
+             || (operand_equal_p (n0, a1, 0)
+                 && operand_equal_p (n1, a0, 0)))
+           return fold_build2_loc (loc, TRUTH_XOR_EXPR, type, l0, n1);
+       }
+
+      if ((tem = fold_truth_andor (loc, code, type, arg0, arg1, op0, op1))
+          != NULL_TREE)
+        return tem;
+
+      return NULL_TREE;
 
     case TRUTH_XOR_EXPR:
       /* If the second arg is constant zero, drop it.  */
@@ -11913,6 +12444,9 @@ fold_binary_loc (location_t loc,
 
     case EQ_EXPR:
     case NE_EXPR:
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+
       tem = fold_comparison (loc, code, type, op0, op1);
       if (tem != NULL_TREE)
        return tem;
@@ -11930,14 +12464,16 @@ fold_binary_loc (location_t loc,
       /* bool_var != 1 becomes !bool_var. */
       if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
           && code == NE_EXPR)
-        return fold_build1_loc (loc, TRUTH_NOT_EXPR, type,
-                           fold_convert_loc (loc, type, arg0));
+        return fold_convert_loc (loc, type,
+                                fold_build1_loc (loc, TRUTH_NOT_EXPR,
+                                                 TREE_TYPE (arg0), arg0));
 
       /* bool_var == 0 becomes !bool_var. */
       if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
           && code == EQ_EXPR)
-        return fold_build1_loc (loc, TRUTH_NOT_EXPR, type,
-                           fold_convert_loc (loc, type, arg0));
+        return fold_convert_loc (loc, type,
+                                fold_build1_loc (loc, TRUTH_NOT_EXPR,
+                                                 TREE_TYPE (arg0), arg0));
 
       /* !exp != 0 becomes !exp */
       if (TREE_CODE (arg0) == TRUTH_NOT_EXPR && integer_zerop (arg1)
@@ -11988,14 +12524,15 @@ fold_binary_loc (location_t loc,
                                      ? MINUS_EXPR : PLUS_EXPR,
                                      fold_convert_loc (loc, TREE_TYPE (arg0),
                                                        arg1),
-                                     TREE_OPERAND (arg0, 1), 0))
+                                     TREE_OPERAND (arg0, 1)))
          && !TREE_OVERFLOW (tem))
        return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem);
 
       /* Similarly for a NEGATE_EXPR.  */
       if (TREE_CODE (arg0) == NEGATE_EXPR
          && TREE_CODE (arg1) == INTEGER_CST
-         && 0 != (tem = negate_expr (arg1))
+         && 0 != (tem = negate_expr (fold_convert_loc (loc, TREE_TYPE (arg0),
+                                                       arg1)))
          && TREE_CODE (tem) == INTEGER_CST
          && !TREE_OVERFLOW (tem))
        return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), tem);
@@ -12015,7 +12552,9 @@ fold_binary_loc (location_t loc,
       if ((TREE_CODE (arg0) == PLUS_EXPR
           || TREE_CODE (arg0) == POINTER_PLUS_EXPR
           || TREE_CODE (arg0) == MINUS_EXPR)
-         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg0,
+                                                                       0)),
+                             arg1, 0)
          && (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
              || POINTER_TYPE_P (TREE_TYPE (arg0))))
        {
@@ -12031,7 +12570,9 @@ fold_binary_loc (location_t loc,
       /* Transform comparisons of the form C - X CMP X if C % 2 == 1.  */
       if (TREE_CODE (arg0) == MINUS_EXPR
          && TREE_CODE (TREE_OPERAND (arg0, 0)) == INTEGER_CST
-         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)
+         && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg0,
+                                                                       1)),
+                             arg1, 0)
          && (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 0)) & 1) == 1)
        {
          return omit_two_operands_loc (loc, type,
@@ -12135,7 +12676,8 @@ fold_binary_loc (location_t loc,
                {
                  tem = fold_build2_loc (loc, LSHIFT_EXPR, itype, arg01, arg001);
                  tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, arg000, tem);
-                 return fold_build2_loc (loc, code, type, tem, arg1);
+                 return fold_build2_loc (loc, code, type, tem,
+                                         fold_convert_loc (loc, itype, arg1));
                }
              /* Otherwise, for signed (arithmetic) shifts,
                 ((X >> C1) & C2) != 0 is rewritten as X < 0, and
@@ -12154,14 +12696,6 @@ fold_binary_loc (location_t loc,
            }
        }
 
-      /* If this is an NE comparison of zero with an AND of one, remove the
-        comparison since the AND will give the correct value.  */
-      if (code == NE_EXPR
-         && integer_zerop (arg1)
-         && TREE_CODE (arg0) == BIT_AND_EXPR
-         && integer_onep (TREE_OPERAND (arg0, 1)))
-       return fold_convert_loc (loc, type, arg0);
-
       /* If we have (A & C) == C where C is a power of 2, convert this into
         (A & C) != 0.  Similarly for NE_EXPR.  */
       if (TREE_CODE (arg0) == BIT_AND_EXPR
@@ -12186,8 +12720,10 @@ fold_binary_loc (location_t loc,
          tree notc = fold_build1_loc (loc, BIT_NOT_EXPR,
                                   TREE_TYPE (TREE_OPERAND (arg0, 1)),
                                   TREE_OPERAND (arg0, 1));
-         tree dandnotc = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
-                                      arg1, notc);
+         tree dandnotc
+           = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
+                              fold_convert_loc (loc, TREE_TYPE (arg0), arg1),
+                              notc);
          tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
          if (integer_nonzerop (dandnotc))
            return omit_one_operand_loc (loc, type, rslt, arg0);
@@ -12200,8 +12736,10 @@ fold_binary_loc (location_t loc,
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
        {
          tree notd = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg1), arg1);
-         tree candnotd = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
-                                      TREE_OPERAND (arg0, 1), notd);
+         tree candnotd
+           = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
+                              TREE_OPERAND (arg0, 1),
+                              fold_convert_loc (loc, TREE_TYPE (arg0), notd));
          tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
          if (integer_nonzerop (candnotd))
            return omit_one_operand_loc (loc, type, rslt, arg0);
@@ -12276,13 +12814,13 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg0) == BIT_XOR_EXPR
          && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
        return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
-                           build_int_cst (TREE_TYPE (arg1), 0));
+                               build_int_cst (TREE_TYPE (arg0), 0));
       /* Likewise (X ^ Y) == X becomes Y == 0.  X has no side-effects.  */
       if (TREE_CODE (arg0) == BIT_XOR_EXPR
          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
          && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
        return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 1),
-                           build_int_cst (TREE_TYPE (arg1), 0));
+                               build_int_cst (TREE_TYPE (arg0), 0));
 
       /* (X ^ C1) op C2 can be rewritten as X op (C1 ^ C2).  */
       if (TREE_CODE (arg0) == BIT_XOR_EXPR
@@ -12300,10 +12838,12 @@ fold_binary_loc (location_t loc,
          && integer_pow2p (TREE_OPERAND (arg0, 1)))
        {
          tem = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
-                            TREE_OPERAND (TREE_OPERAND (arg0, 0), 0),
-                            TREE_OPERAND (arg0, 1));
+                                TREE_OPERAND (TREE_OPERAND (arg0, 0), 0),
+                                TREE_OPERAND (arg0, 1));
          return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR,
-                             type, tem, arg1);
+                                 type, tem,
+                                 fold_convert_loc (loc, TREE_TYPE (arg0),
+                                                   arg1));
        }
 
       /* Fold ((X & C) ^ C) eq/ne 0 into (X & C) ne/eq 0, when the
@@ -12347,8 +12887,9 @@ fold_binary_loc (location_t loc,
       if (TREE_CODE (arg0) == NEGATE_EXPR
           && TREE_CODE (arg1) == NEGATE_EXPR)
        return fold_build2_loc (loc, code, type,
-                           TREE_OPERAND (arg0, 0),
-                           TREE_OPERAND (arg1, 0));
+                               TREE_OPERAND (arg0, 0),
+                               fold_convert_loc (loc, TREE_TYPE (arg0),
+                                                 TREE_OPERAND (arg1, 0)));
 
       /* Fold (X & C) op (Y & C) as (X ^ Y) & C op 0", and symmetries.  */
       if (TREE_CODE (arg0) == BIT_AND_EXPR
@@ -12410,23 +12951,32 @@ fold_binary_loc (location_t loc,
             operand_equal_p guarantees no side-effects so we don't need
             to use omit_one_operand on Z.  */
          if (operand_equal_p (arg01, arg11, 0))
-           return fold_build2_loc (loc, code, type, arg00, arg10);
+           return fold_build2_loc (loc, code, type, arg00,
+                                   fold_convert_loc (loc, TREE_TYPE (arg00),
+                                                     arg10));
          if (operand_equal_p (arg01, arg10, 0))
-           return fold_build2_loc (loc, code, type, arg00, arg11);
+           return fold_build2_loc (loc, code, type, arg00,
+                                   fold_convert_loc (loc, TREE_TYPE (arg00),
+                                                     arg11));
          if (operand_equal_p (arg00, arg11, 0))
-           return fold_build2_loc (loc, code, type, arg01, arg10);
+           return fold_build2_loc (loc, code, type, arg01,
+                                   fold_convert_loc (loc, TREE_TYPE (arg01),
+                                                     arg10));
          if (operand_equal_p (arg00, arg10, 0))
-           return fold_build2_loc (loc, code, type, arg01, arg11);
+           return fold_build2_loc (loc, code, type, arg01,
+                                   fold_convert_loc (loc, TREE_TYPE (arg01),
+                                                     arg11));
 
          /* Optimize (X ^ C1) op (Y ^ C2) as (X ^ (C1 ^ C2)) op Y.  */
          if (TREE_CODE (arg01) == INTEGER_CST
              && TREE_CODE (arg11) == INTEGER_CST)
-           return fold_build2_loc (loc, code, type,
-                               fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00,
-                                            fold_build2_loc (loc,
-                                                         BIT_XOR_EXPR, itype,
-                                                         arg01, arg11)),
-                               arg10);
+           {
+             tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg01,
+                                    fold_convert_loc (loc, itype, arg11));
+             tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00, tem);
+             return fold_build2_loc (loc, code, type, tem,
+                                     fold_convert_loc (loc, itype, arg10));
+           }
        }
 
       /* Attempt to simplify equality/inequality comparisons of complex
@@ -12724,14 +13274,14 @@ fold_binary_loc (location_t loc,
                {
                case GT_EXPR:
                  arg1 = const_binop (PLUS_EXPR, arg1,
-                                     build_int_cst (TREE_TYPE (arg1), 1), 0);
+                                     build_int_cst (TREE_TYPE (arg1), 1));
                  return fold_build2_loc (loc, EQ_EXPR, type,
                                      fold_convert_loc (loc,
                                                        TREE_TYPE (arg1), arg0),
                                      arg1);
                case LE_EXPR:
                  arg1 = const_binop (PLUS_EXPR, arg1,
-                                     build_int_cst (TREE_TYPE (arg1), 1), 0);
+                                     build_int_cst (TREE_TYPE (arg1), 1));
                  return fold_build2_loc (loc, NE_EXPR, type,
                                      fold_convert_loc (loc, TREE_TYPE (arg1),
                                                        arg0),
@@ -12765,13 +13315,13 @@ fold_binary_loc (location_t loc,
              switch (code)
                {
                case GE_EXPR:
-                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node);
                  return fold_build2_loc (loc, NE_EXPR, type,
                                      fold_convert_loc (loc,
                                                        TREE_TYPE (arg1), arg0),
                                      arg1);
                case LT_EXPR:
-                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+                 arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node);
                  return fold_build2_loc (loc, EQ_EXPR, type,
                                      fold_convert_loc (loc, TREE_TYPE (arg1),
                                                        arg0),
@@ -12860,13 +13410,10 @@ fold_binary_loc (location_t loc,
          && TYPE_UNSIGNED (TREE_TYPE (arg0))
          && TREE_CODE (arg1) == LSHIFT_EXPR
          && integer_onep (TREE_OPERAND (arg1, 0)))
-       {
-         tem = build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
-                       build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
-                               TREE_OPERAND (arg1, 1)),
-                       build_int_cst (TREE_TYPE (arg0), 0));
-         goto fold_binary_exit;
-       }
+       return build2_loc (loc, code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+                          build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+                                  TREE_OPERAND (arg1, 1)),
+                          build_int_cst (TREE_TYPE (arg0), 0));
 
       if ((code == LT_EXPR || code == GE_EXPR)
          && TYPE_UNSIGNED (TREE_TYPE (arg0))
@@ -12874,14 +13421,11 @@ fold_binary_loc (location_t loc,
          && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
          && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
        {
-         tem = build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
-                       fold_convert_loc (loc, TREE_TYPE (arg0),
-                                         build2 (RSHIFT_EXPR,
-                                                 TREE_TYPE (arg0), arg0,
-                                                 TREE_OPERAND (TREE_OPERAND (arg1, 0),
-                                                               1))),
-                       build_int_cst (TREE_TYPE (arg0), 0));
-         goto fold_binary_exit;
+         tem = build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+                       TREE_OPERAND (TREE_OPERAND (arg1, 0), 1));
+         return build2_loc (loc, code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+                            fold_convert_loc (loc, TREE_TYPE (arg0), tem),
+                            build_int_cst (TREE_TYPE (arg0), 0));
        }
 
       return NULL_TREE;
@@ -12966,18 +13510,89 @@ fold_binary_loc (location_t loc,
          || (TREE_CODE (arg0) == INTEGER_CST
              && TREE_CODE (arg1) == INTEGER_CST))
        return build_complex (type, arg0, arg1);
+      if (TREE_CODE (arg0) == REALPART_EXPR
+         && TREE_CODE (arg1) == IMAGPART_EXPR
+         && TREE_TYPE (TREE_OPERAND (arg0, 0)) == type
+         && operand_equal_p (TREE_OPERAND (arg0, 0),
+                             TREE_OPERAND (arg1, 0), 0))
+       return omit_one_operand_loc (loc, type, TREE_OPERAND (arg0, 0),
+                                    TREE_OPERAND (arg1, 0));
       return NULL_TREE;
 
     case ASSERT_EXPR:
       /* An ASSERT_EXPR should never be passed to fold_binary.  */
       gcc_unreachable ();
 
+    case VEC_PACK_TRUNC_EXPR:
+    case VEC_PACK_FIX_TRUNC_EXPR:
+      {
+       unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
+       tree *elts, vals = NULL_TREE;
+
+       gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts / 2
+                   && TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)) == nelts / 2);
+       if (TREE_CODE (arg0) != VECTOR_CST || TREE_CODE (arg1) != VECTOR_CST)
+         return NULL_TREE;
+
+       elts = XALLOCAVEC (tree, nelts);
+       if (!vec_cst_ctor_to_array (arg0, elts)
+           || !vec_cst_ctor_to_array (arg1, elts + nelts / 2))
+         return NULL_TREE;
+
+       for (i = 0; i < nelts; i++)
+         {
+           elts[i] = fold_convert_const (code == VEC_PACK_TRUNC_EXPR
+                                         ? NOP_EXPR : FIX_TRUNC_EXPR,
+                                         TREE_TYPE (type), elts[i]);
+           if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i]))
+             return NULL_TREE;
+         }
+
+       for (i = 0; i < nelts; i++)
+         vals = tree_cons (NULL_TREE, elts[nelts - i - 1], vals);
+       return build_vector (type, vals);
+      }
+
+    case VEC_WIDEN_MULT_LO_EXPR:
+    case VEC_WIDEN_MULT_HI_EXPR:
+      {
+       unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
+       tree *elts, vals = NULL_TREE;
+
+       gcc_assert (TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)) == nelts * 2
+                   && TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg1)) == nelts * 2);
+       if (TREE_CODE (arg0) != VECTOR_CST || TREE_CODE (arg1) != VECTOR_CST)
+         return NULL_TREE;
+
+       elts = XALLOCAVEC (tree, nelts * 4);
+       if (!vec_cst_ctor_to_array (arg0, elts)
+           || !vec_cst_ctor_to_array (arg1, elts + nelts * 2))
+         return NULL_TREE;
+
+       if ((!BYTES_BIG_ENDIAN) ^ (code == VEC_WIDEN_MULT_LO_EXPR))
+         elts += nelts;
+
+       for (i = 0; i < nelts; i++)
+         {
+           elts[i] = fold_convert_const (NOP_EXPR, TREE_TYPE (type), elts[i]);
+           elts[i + nelts * 2]
+             = fold_convert_const (NOP_EXPR, TREE_TYPE (type),
+                                   elts[i + nelts * 2]);
+           if (elts[i] == NULL_TREE || elts[i + nelts * 2] == NULL_TREE)
+             return NULL_TREE;
+           elts[i] = const_binop (MULT_EXPR, elts[i], elts[i + nelts * 2]);
+           if (elts[i] == NULL_TREE || !CONSTANT_CLASS_P (elts[i]))
+             return NULL_TREE;
+         }
+
+       for (i = 0; i < nelts; i++)
+         vals = tree_cons (NULL_TREE, elts[nelts - i - 1], vals);
+       return build_vector (type, vals);
+      }
+
     default:
       return NULL_TREE;
     } /* switch (code) */
- fold_binary_exit:
-  protected_set_expr_location (tem, loc);
-  return tem;
 }
 
 /* Callback for walk_tree, looking for LABEL_EXPR.  Return *TP if it is
@@ -13018,10 +13633,10 @@ contains_label_p (tree st)
 
 tree
 fold_ternary_loc (location_t loc, enum tree_code code, tree type,
-             tree op0, tree op1, tree op2)
+                 tree op0, tree op1, tree op2)
 {
   tree tem;
-  tree arg0 = NULL_TREE, arg1 = NULL_TREE;
+  tree arg0 = NULL_TREE, arg1 = NULL_TREE, arg2 = NULL_TREE;
   enum tree_code_class kind = TREE_CODE_CLASS (code);
 
   gcc_assert (IS_EXPR_CODE_CLASS (kind)
@@ -13049,6 +13664,12 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
       STRIP_NOPS (arg1);
     }
 
+  if (op2)
+    {
+      arg2 = op2;
+      STRIP_NOPS (arg2);
+    }
+
   switch (code)
     {
     case COMPONENT_REF:
@@ -13106,7 +13727,8 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
                                             TREE_OPERAND (arg0, 1))
          && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2))))
        {
-         tem = fold_truth_not_expr (loc, arg0);
+         location_t loc0 = expr_location_or (arg0, loc);
+         tem = fold_truth_not_expr (loc0, arg0);
          if (tem && COMPARISON_CLASS_P (tem))
            {
              tem = fold_cond_expr_with_comparison (loc, type, tem, op2, op1);
@@ -13120,10 +13742,11 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
       if (truth_value_p (TREE_CODE (arg0))
          && tree_swap_operands_p (op1, op2, false))
        {
+         location_t loc0 = expr_location_or (arg0, loc);
          /* See if this can be inverted.  If it can't, possibly because
             it was a floating-point inequality comparison, don't do
             anything.  */
-         tem = fold_truth_not_expr (loc, arg0);
+         tem = fold_truth_not_expr (loc0, arg0);
          if (tem)
            return fold_build3_loc (loc, code, type, tem, op2, op1);
        }
@@ -13268,8 +13891,9 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
          && truth_value_p (TREE_CODE (arg0))
          && truth_value_p (TREE_CODE (arg1)))
        {
+         location_t loc0 = expr_location_or (arg0, loc);
          /* Only perform transformation if ARG0 is easily inverted.  */
-         tem = fold_truth_not_expr (loc, arg0);
+         tem = fold_truth_not_expr (loc0, arg0);
          if (tem)
            return fold_build2_loc (loc, TRUTH_ORIF_EXPR, type,
                                fold_convert_loc (loc, type, tem),
@@ -13281,8 +13905,9 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
          && truth_value_p (TREE_CODE (arg0))
          && truth_value_p (TREE_CODE (op2)))
        {
+         location_t loc0 = expr_location_or (arg0, loc);
          /* Only perform transformation if ARG0 is easily inverted.  */
-         tem = fold_truth_not_expr (loc, arg0);
+         tem = fold_truth_not_expr (loc0, arg0);
          if (tem)
            return fold_build2_loc (loc, TRUTH_ANDIF_EXPR, type,
                                fold_convert_loc (loc, type, tem),
@@ -13306,7 +13931,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
 
     case BIT_FIELD_REF:
       if ((TREE_CODE (arg0) == VECTOR_CST
-          || (TREE_CODE (arg0) == CONSTRUCTOR && TREE_CONSTANT (arg0)))
+          || TREE_CODE (arg0) == CONSTRUCTOR)
          && type == TREE_TYPE (TREE_TYPE (arg0)))
        {
          unsigned HOST_WIDE_INT width = tree_low_cst (arg1, 1);
@@ -13318,24 +13943,17 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
              && (idx = idx / width)
                 < TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))
            {
-             tree elements = NULL_TREE;
-
              if (TREE_CODE (arg0) == VECTOR_CST)
-               elements = TREE_VECTOR_CST_ELTS (arg0);
-             else
                {
-                 unsigned HOST_WIDE_INT idx;
-                 tree value;
-
-                 FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (arg0), idx, value)
-                   elements = tree_cons (NULL_TREE, value, elements);
+                 tree elements = TREE_VECTOR_CST_ELTS (arg0);
+                 while (idx-- > 0 && elements)
+                   elements = TREE_CHAIN (elements);
+                 if (elements)
+                   return TREE_VALUE (elements);
                }
-             while (idx-- > 0 && elements)
-               elements = TREE_CHAIN (elements);
-             if (elements)
-               return TREE_VALUE (elements);
-             else
-               return fold_convert_loc (loc, type, integer_zero_node);
+             else if (idx < CONSTRUCTOR_NELTS (arg0))
+               return CONSTRUCTOR_ELT (arg0, idx)->value;
+             return build_zero_cst (type);
            }
        }
 
@@ -13347,6 +13965,66 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
 
       return NULL_TREE;
 
+    case FMA_EXPR:
+      /* For integers we can decompose the FMA if possible.  */
+      if (TREE_CODE (arg0) == INTEGER_CST
+         && TREE_CODE (arg1) == INTEGER_CST)
+       return fold_build2_loc (loc, PLUS_EXPR, type,
+                               const_binop (MULT_EXPR, arg0, arg1), arg2);
+      if (integer_zerop (arg2))
+       return fold_build2_loc (loc, MULT_EXPR, type, arg0, arg1);
+
+      return fold_fma (loc, type, arg0, arg1, arg2);
+
+    case VEC_PERM_EXPR:
+      if (TREE_CODE (arg2) == VECTOR_CST)
+       {
+         unsigned int nelts = TYPE_VECTOR_SUBPARTS (type), i;
+         unsigned char *sel = XALLOCAVEC (unsigned char, nelts);
+         tree t;
+         bool need_mask_canon = false;
+
+         gcc_assert (nelts == TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg2)));
+         for (i = 0, t = TREE_VECTOR_CST_ELTS (arg2);
+              i < nelts && t; i++, t = TREE_CHAIN (t))
+           {
+             if (TREE_CODE (TREE_VALUE (t)) != INTEGER_CST)
+               return NULL_TREE;
+
+             sel[i] = TREE_INT_CST_LOW (TREE_VALUE (t)) & (2 * nelts - 1);
+             if (TREE_INT_CST_HIGH (TREE_VALUE (t))
+                 || ((unsigned HOST_WIDE_INT)
+                     TREE_INT_CST_LOW (TREE_VALUE (t)) != sel[i]))
+               need_mask_canon = true;
+           }
+         if (t)
+           return NULL_TREE;
+         for (; i < nelts; i++)
+           sel[i] = 0;
+
+         if ((TREE_CODE (arg0) == VECTOR_CST
+              || TREE_CODE (arg0) == CONSTRUCTOR)
+             && (TREE_CODE (arg1) == VECTOR_CST
+                 || TREE_CODE (arg1) == CONSTRUCTOR))
+           {
+             t = fold_vec_perm (type, arg0, arg1, sel);
+             if (t != NULL_TREE)
+               return t;
+           }
+
+         if (need_mask_canon && arg2 == op2)
+           {
+             tree list = NULL_TREE, eltype = TREE_TYPE (TREE_TYPE (arg2));
+             for (i = 0; i < nelts; i++)
+               list = tree_cons (NULL_TREE,
+                                 build_int_cst (eltype, sel[nelts - i - 1]),
+                                 list);
+             t = build_vector (TREE_TYPE (arg2), list);
+             return build3_loc (loc, VEC_PERM_EXPR, type, op0, op1, t);
+           }
+       }
+      return NULL_TREE;
+
     default:
       return NULL_TREE;
     } /* switch (code) */
@@ -13530,22 +14208,18 @@ fold_check_failed (const_tree expr ATTRIBUTE_UNUSED, const_tree ret ATTRIBUTE_UN
 static void
 fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, htab_t ht)
 {
-  const void **slot;
+  void **slot;
   enum tree_code code;
   union tree_node buf;
   int i, len;
 
-recursive_label:
-
-  gcc_assert ((sizeof (struct tree_exp) + 5 * sizeof (tree)
-              <= sizeof (struct tree_function_decl))
-             && sizeof (struct tree_type) <= sizeof (struct tree_function_decl));
+ recursive_label:
   if (expr == NULL)
     return;
-  slot = (const void **) htab_find_slot (ht, expr, INSERT);
+  slot = (void **) htab_find_slot (ht, expr, INSERT);
   if (*slot != NULL)
     return;
-  *slot = expr;
+  *slot = CONST_CAST_TREE (expr);
   code = TREE_CODE (expr);
   if (TREE_CODE_CLASS (code) == tcc_declaration
       && DECL_ASSEMBLER_NAME_SET_P (expr))
@@ -13577,11 +14251,13 @@ recursive_label:
        }
     }
   md5_process_bytes (expr, tree_size (expr), ctx);
-  fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
+  if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
+    fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
   if (TREE_CODE_CLASS (code) != tcc_type
       && TREE_CODE_CLASS (code) != tcc_declaration
       && code != TREE_LIST
-      && code != SSA_NAME)
+      && code != SSA_NAME
+      && CODE_CONTAINS_STRUCT (code, TS_COMMON))
     fold_checksum_tree (TREE_CHAIN (expr), ctx, ht);
   switch (TREE_CODE_CLASS (code))
     {
@@ -13682,7 +14358,7 @@ recursive_label:
    by "call debug_fold_checksum (op0)", then just trace down till the
    outputs differ.  */
 
-void
+DEBUG_FUNCTION void
 debug_fold_checksum (const_tree t)
 {
   int i;
@@ -13727,10 +14403,7 @@ fold_build1_stat_loc (location_t loc,
 
   tem = fold_unary_loc (loc, code, type, op0);
   if (!tem)
-    {
-      tem = build1_stat (code, type, op0 PASS_MEM_STAT);
-      SET_EXPR_LOCATION (tem, loc);
-    }
+    tem = build1_stat_loc (loc, code, type, op0 PASS_MEM_STAT);
 
 #ifdef ENABLE_FOLD_CHECKING
   md5_init_ctx (&ctx);
@@ -13778,10 +14451,7 @@ fold_build2_stat_loc (location_t loc,
 
   tem = fold_binary_loc (loc, code, type, op0, op1);
   if (!tem)
-    {
-      tem = build2_stat (code, type, op0, op1 PASS_MEM_STAT);
-      SET_EXPR_LOCATION (tem, loc);
-    }
+    tem = build2_stat_loc (loc, code, type, op0, op1 PASS_MEM_STAT);
 
 #ifdef ENABLE_FOLD_CHECKING
   md5_init_ctx (&ctx);
@@ -13843,10 +14513,7 @@ fold_build3_stat_loc (location_t loc, enum tree_code code, tree type,
   gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
   tem = fold_ternary_loc (loc, code, type, op0, op1, op2);
   if (!tem)
-    {
-      tem =  build3_stat (code, type, op0, op1, op2 PASS_MEM_STAT);
-      SET_EXPR_LOCATION (tem, loc);
-    }
+    tem = build3_stat_loc (loc, code, type, op0, op1, op2 PASS_MEM_STAT);
 
 #ifdef ENABLE_FOLD_CHECKING
   md5_init_ctx (&ctx);
@@ -14090,7 +14757,7 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
              && 0 != (t1 = fold_convert (type,
                                          const_binop (LSHIFT_EXPR,
                                                       size_one_node,
-                                                      op1, 0)))
+                                                      op1)))
              && !TREE_OVERFLOW (t1))
            return multiple_of_p (type, t1, bottom);
        }
@@ -14120,7 +14787,7 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
                  || tree_int_cst_sgn (bottom) < 0)))
        return 0;
       return integer_zerop (int_const_binop (TRUNC_MOD_EXPR,
-                                            top, bottom, 0));
+                                            top, bottom));
 
     default:
       return 0;
@@ -14418,6 +15085,10 @@ tree_call_nonnegative_warnv_p (tree type, tree fndecl,
        CASE_FLT_FN (BUILT_IN_FLOOR):
        CASE_FLT_FN (BUILT_IN_FMOD):
        CASE_FLT_FN (BUILT_IN_FREXP):
+       CASE_FLT_FN (BUILT_IN_ICEIL):
+       CASE_FLT_FN (BUILT_IN_IFLOOR):
+       CASE_FLT_FN (BUILT_IN_IRINT):
+       CASE_FLT_FN (BUILT_IN_IROUND):
        CASE_FLT_FN (BUILT_IN_LCEIL):
        CASE_FLT_FN (BUILT_IN_LDEXP):
        CASE_FLT_FN (BUILT_IN_LFLOOR):
@@ -14831,7 +15502,9 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p)
 
     case ADDR_EXPR:
       {
-       tree base = get_base_address (TREE_OPERAND (t, 0));
+       tree base = TREE_OPERAND (t, 0);
+       if (!DECL_P (base))
+         base = get_base_address (base);
 
        if (!base)
          return false;
@@ -14841,7 +15514,9 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p)
           allocated on the stack.  */
        if (DECL_P (base)
            && (flag_delete_null_pointer_checks
-               || (TREE_CODE (base) == VAR_DECL && !TREE_STATIC (base))))
+               || (DECL_CONTEXT (base)
+                   && TREE_CODE (DECL_CONTEXT (base)) == FUNCTION_DECL
+                   && auto_var_in_fn_p (base, DECL_CONTEXT (base)))))
          return !VAR_OR_FUNCTION_DECL_P (base) || !DECL_WEAK (base);
 
        /* Constants are never weak.  */
@@ -15065,19 +15740,17 @@ fold_negate_const (tree arg0, tree type)
     {
     case INTEGER_CST:
       {
-       unsigned HOST_WIDE_INT low;
-       HOST_WIDE_INT high;
-       int overflow = neg_double (TREE_INT_CST_LOW (arg0),
-                                  TREE_INT_CST_HIGH (arg0),
-                                  &low, &high);
-       t = force_fit_type_double (type, low, high, 1,
+       double_int val = tree_to_double_int (arg0);
+       int overflow = neg_double (val.low, val.high, &val.low, &val.high);
+
+       t = force_fit_type_double (type, val, 1,
                                   (overflow | TREE_OVERFLOW (arg0))
                                   && !TYPE_UNSIGNED (type));
        break;
       }
 
     case REAL_CST:
-      t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
+      t = build_real (type, real_value_negate (&TREE_REAL_CST (arg0)));
       break;
 
     case FIXED_CST:
@@ -15113,30 +15786,31 @@ fold_abs_const (tree arg0, tree type)
   switch (TREE_CODE (arg0))
     {
     case INTEGER_CST:
-      /* If the value is unsigned, then the absolute value is
-        the same as the ordinary value.  */
-      if (TYPE_UNSIGNED (type))
-       t = arg0;
-      /* Similarly, if the value is non-negative.  */
-      else if (INT_CST_LT (integer_minus_one_node, arg0))
-       t = arg0;
-      /* If the value is negative, then the absolute value is
-        its negation.  */
-      else
-       {
-         unsigned HOST_WIDE_INT low;
-         HOST_WIDE_INT high;
-         int overflow = neg_double (TREE_INT_CST_LOW (arg0),
-                                    TREE_INT_CST_HIGH (arg0),
-                                    &low, &high);
-         t = force_fit_type_double (type, low, high, -1,
-                                    overflow | TREE_OVERFLOW (arg0));
-       }
+      {
+       double_int val = tree_to_double_int (arg0);
+
+        /* If the value is unsigned or non-negative, then the absolute value
+          is the same as the ordinary value.  */
+       if (TYPE_UNSIGNED (type)
+           || !double_int_negative_p (val))
+         t = arg0;
+
+       /* If the value is negative, then the absolute value is
+          its negation.  */
+       else
+         {
+           int overflow;
+
+           overflow = neg_double (val.low, val.high, &val.low, &val.high);
+           t = force_fit_type_double (type, val, -1,
+                                      overflow | TREE_OVERFLOW (arg0));
+         }
+      }
       break;
 
     case REAL_CST:
       if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0)))
-       t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
+       t = build_real (type, real_value_negate (&TREE_REAL_CST (arg0)));
       else
        t =  arg0;
       break;
@@ -15152,17 +15826,14 @@ fold_abs_const (tree arg0, tree type)
    constant.  TYPE is the type of the result.  */
 
 static tree
-fold_not_const (tree arg0, tree type)
+fold_not_const (const_tree arg0, tree type)
 {
-  tree t = NULL_TREE;
+  double_int val;  
 
   gcc_assert (TREE_CODE (arg0) == INTEGER_CST);
 
-  t = force_fit_type_double (type, ~TREE_INT_CST_LOW (arg0),
-                            ~TREE_INT_CST_HIGH (arg0), 0,
-                            TREE_OVERFLOW (arg0));
-
-  return t;
+  val = double_int_not (tree_to_double_int (arg0));
+  return force_fit_type_double (type, val, 0, TREE_OVERFLOW (arg0));
 }
 
 /* Given CODE, a relational operator, the target type, TYPE and two
@@ -15356,15 +16027,19 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0)
        }
       /* *(foo *)&fooarray => fooarray[0] */
       else if (TREE_CODE (optype) == ARRAY_TYPE
-              && type == TREE_TYPE (optype))
+              && type == TREE_TYPE (optype)
+              && (!in_gimple_form
+                  || TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
        {
          tree type_domain = TYPE_DOMAIN (optype);
          tree min_val = size_zero_node;
          if (type_domain && TYPE_MIN_VALUE (type_domain))
            min_val = TYPE_MIN_VALUE (type_domain);
-         op0 = build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
-         SET_EXPR_LOCATION (op0, loc);
-         return op0;
+         if (in_gimple_form
+             && TREE_CODE (min_val) != INTEGER_CST)
+           return NULL_TREE;
+         return build4_loc (loc, ARRAY_REF, type, op, min_val,
+                            NULL_TREE, NULL_TREE);
        }
       /* *(foo *)&complexfoo => __real__ complexfoo */
       else if (TREE_CODE (optype) == COMPLEX_TYPE
@@ -15380,59 +16055,65 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0)
        }
     }
 
-  /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
   if (TREE_CODE (sub) == POINTER_PLUS_EXPR
       && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
     {
       tree op00 = TREE_OPERAND (sub, 0);
       tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
 
       STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-          && TREE_CODE (TREE_TYPE (op00type)) == VECTOR_TYPE
-          && type == TREE_TYPE (TREE_TYPE (op00type)))
+      if (TREE_CODE (op00) == ADDR_EXPR)
        {
-         HOST_WIDE_INT offset = tree_low_cst (op01, 0);
-         tree part_width = TYPE_SIZE (type);
-         unsigned HOST_WIDE_INT part_widthi = tree_low_cst (part_width, 0)/BITS_PER_UNIT;
-         unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
-         tree index = bitsize_int (indexi);
-
-         if (offset/part_widthi <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (op00type)))
-           return fold_build3_loc (loc,
-                               BIT_FIELD_REF, type, TREE_OPERAND (op00, 0),
-                               part_width, index);
-
-       }
-    }
+         tree op00type;
+         op00 = TREE_OPERAND (op00, 0);
+         op00type = TREE_TYPE (op00);
 
+         /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
+         if (TREE_CODE (op00type) == VECTOR_TYPE
+             && type == TREE_TYPE (op00type))
+           {
+             HOST_WIDE_INT offset = tree_low_cst (op01, 0);
+             tree part_width = TYPE_SIZE (type);
+             unsigned HOST_WIDE_INT part_widthi = tree_low_cst (part_width, 0)/BITS_PER_UNIT;
+             unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
+             tree index = bitsize_int (indexi);
 
-  /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
-  if (TREE_CODE (sub) == POINTER_PLUS_EXPR
-      && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
-    {
-      tree op00 = TREE_OPERAND (sub, 0);
-      tree op01 = TREE_OPERAND (sub, 1);
-      tree op00type;
+             if (offset/part_widthi <= TYPE_VECTOR_SUBPARTS (op00type))
+               return fold_build3_loc (loc,
+                                       BIT_FIELD_REF, type, op00,
+                                       part_width, index);
 
-      STRIP_NOPS (op00);
-      op00type = TREE_TYPE (op00);
-      if (TREE_CODE (op00) == ADDR_EXPR
-         && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE
-         && type == TREE_TYPE (TREE_TYPE (op00type)))
-       {
-         tree size = TYPE_SIZE_UNIT (type);
-         if (tree_int_cst_equal (size, op01))
-           return fold_build1_loc (loc, IMAGPART_EXPR, type,
-                               TREE_OPERAND (op00, 0));
+           }
+         /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+         else if (TREE_CODE (op00type) == COMPLEX_TYPE
+                  && type == TREE_TYPE (op00type))
+           {
+             tree size = TYPE_SIZE_UNIT (type);
+             if (tree_int_cst_equal (size, op01))
+               return fold_build1_loc (loc, IMAGPART_EXPR, type, op00);
+           }
+         /* ((foo *)&fooarray)[1] => fooarray[1] */
+         else if (TREE_CODE (op00type) == ARRAY_TYPE
+                  && type == TREE_TYPE (op00type))
+           {
+             tree type_domain = TYPE_DOMAIN (op00type);
+             tree min_val = size_zero_node;
+             if (type_domain && TYPE_MIN_VALUE (type_domain))
+               min_val = TYPE_MIN_VALUE (type_domain);
+             op01 = size_binop_loc (loc, EXACT_DIV_EXPR, op01,
+                                    TYPE_SIZE_UNIT (type));
+             op01 = size_binop_loc (loc, PLUS_EXPR, op01, min_val);
+             return build4_loc (loc, ARRAY_REF, type, op00, op01,
+                                NULL_TREE, NULL_TREE);
+           }
        }
     }
 
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
   if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
-      && type == TREE_TYPE (TREE_TYPE (subtype)))
+      && type == TREE_TYPE (TREE_TYPE (subtype))
+      && (!in_gimple_form
+         || TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST))
     {
       tree type_domain;
       tree min_val = size_zero_node;
@@ -15440,9 +16121,11 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0)
       type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
       if (type_domain && TYPE_MIN_VALUE (type_domain))
        min_val = TYPE_MIN_VALUE (type_domain);
-      op0 = build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
-      SET_EXPR_LOCATION (op0, loc);
-      return op0;
+      if (in_gimple_form
+         && TREE_CODE (min_val) != INTEGER_CST)
+       return NULL_TREE;
+      return build4_loc (loc, ARRAY_REF, type, sub, min_val, NULL_TREE,
+                        NULL_TREE);
     }
 
   return NULL_TREE;
@@ -15460,9 +16143,7 @@ build_fold_indirect_ref_loc (location_t loc, tree t)
   if (sub)
     return sub;
 
-  t = build1 (INDIRECT_REF, type, t);
-  SET_EXPR_LOCATION (t, loc);
-  return t;
+  return build1_loc (loc, INDIRECT_REF, type, t);
 }
 
 /* Given an INDIRECT_REF T, return either T or a simplified version.  */
@@ -15560,25 +16241,23 @@ round_up_loc (location_t loc, tree value, int divisor)
     {
       if (TREE_CODE (value) == INTEGER_CST)
        {
-         unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (value);
-         unsigned HOST_WIDE_INT high;
+         double_int val = tree_to_double_int (value);
          bool overflow_p;
 
-         if ((low & (divisor - 1)) == 0)
+         if ((val.low & (divisor - 1)) == 0)
            return value;
 
          overflow_p = TREE_OVERFLOW (value);
-         high = TREE_INT_CST_HIGH (value);
-         low &= ~(divisor - 1);
-         low += divisor;
-         if (low == 0)
+         val.low &= ~(divisor - 1);
+         val.low += divisor;
+         if (val.low == 0)
            {
-             high++;
-             if (high == 0)
+             val.high++;
+             if (val.high == 0)
                overflow_p = true;
            }
 
-         return force_fit_type_double (TREE_TYPE (value), low, high,
+         return force_fit_type_double (TREE_TYPE (value), val,
                                        -1, overflow_p);
        }
       else