OSDN Git Service

2007-08-03 Andrew Pinski <andrew_pinski@playstation.sony.com>
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 7d66736..be46b23 100644 (file)
@@ -7,7 +7,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /*@@ This file should be rewritten to use an arbitrary precision
   @@ representation for "struct tree_int_cst" and "struct tree_real_cst".
@@ -65,7 +64,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "langhooks.h"
 #include "md5.h"
 
-/* Non-zero if we are folding constants inside an initializer; zero
+/* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
 int folding_initializer = 0;
 
@@ -131,7 +130,6 @@ static tree fold_truthop (enum tree_code, tree, tree, tree);
 static tree optimize_minmax_comparison (enum tree_code, tree, tree, tree);
 static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *);
 static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *);
-static int multiple_of_p (tree, tree, tree);
 static tree fold_binary_op_with_conditional_arg (enum tree_code, tree,
                                                 tree, tree,
                                                 tree, tree, int);
@@ -144,8 +142,6 @@ static bool reorder_operands_p (tree, tree);
 static tree fold_negate_const (tree, tree);
 static tree fold_not_const (tree, tree);
 static tree fold_relational_const (enum tree_code, tree, tree, tree);
-static int native_encode_expr (tree, unsigned char *, int);
-static tree native_interpret_expr (tree, unsigned char *, int);
 
 
 /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
@@ -201,7 +197,7 @@ decode (HOST_WIDE_INT *words, unsigned HOST_WIDE_INT *low,
 
 int
 fit_double_type (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
-                unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, tree type)
+                unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, const_tree type)
 {
   unsigned HOST_WIDE_INT low0 = l1;
   HOST_WIDE_INT high0 = h1;
@@ -891,6 +887,17 @@ div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2)
 
   int1l = TREE_INT_CST_LOW (arg1);
   int1h = TREE_INT_CST_HIGH (arg1);
+  /* &obj[0] + -128 really should be compiled as &obj[-8] rather than
+     &obj[some_exotic_number].  */
+  if (POINTER_TYPE_P (type))
+    {
+      uns = false;
+      type = signed_type_for (type);
+      fit_double_type (int1l, int1h, &int1l, &int1h,
+                      type);
+    }
+  else
+    fit_double_type (int1l, int1h, &int1l, &int1h, type);
   int2l = TREE_INT_CST_LOW (arg2);
   int2h = TREE_INT_CST_HIGH (arg2);
 
@@ -902,7 +909,7 @@ div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2)
   return build_int_cst_wide (type, quol, quoh);
 }
 \f
-/* This is non-zero if we should defer warnings about undefined
+/* This is nonzero if we should defer warnings about undefined
    overflow.  This facility exists because these warnings are a
    special case.  The code to estimate loop iterations does not want
    to issue any warnings, since it works with expressions which do not
@@ -1067,7 +1074,7 @@ negate_mathfn_p (enum built_in_function code)
    overflow.  */
 
 bool
-may_negate_without_overflow_p (tree t)
+may_negate_without_overflow_p (const_tree t)
 {
   unsigned HOST_WIDE_INT val;
   unsigned int prec;
@@ -1195,7 +1202,7 @@ negate_expr_p (tree t)
     case CALL_EXPR:
       /* Negate -f(x) as f(-x).  */
       if (negate_mathfn_p (builtin_mathfn_code (t)))
-       return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1)));
+       return negate_expr_p (CALL_EXPR_ARG (t, 0));
       break;
 
     case RSHIFT_EXPR:
@@ -1375,21 +1382,20 @@ fold_negate_expr (tree t)
        {
          tem = strip_float_extensions (t);
          if (tem != t && negate_expr_p (tem))
-           return negate_expr (tem);
+           return fold_convert (type, negate_expr (tem));
        }
       break;
 
     case CALL_EXPR:
       /* Negate -f(x) as f(-x).  */
       if (negate_mathfn_p (builtin_mathfn_code (t))
-         && negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1))))
+         && negate_expr_p (CALL_EXPR_ARG (t, 0)))
        {
-         tree fndecl, arg, arglist;
+         tree fndecl, arg;
 
          fndecl = get_callee_fndecl (t);
-         arg = negate_expr (TREE_VALUE (TREE_OPERAND (t, 1)));
-         arglist = build_tree_list (NULL_TREE, arg);
-         return build_function_call_expr (fndecl, arglist);
+         arg = negate_expr (CALL_EXPR_ARG (t, 0));
+         return build_call_expr (fndecl, 1, arg);
        }
       break;
 
@@ -1403,8 +1409,8 @@ fold_negate_expr (tree t)
                 == TREE_INT_CST_LOW (op1))
            {
              tree ntype = TYPE_UNSIGNED (type)
-                          ? lang_hooks.types.signed_type (type)
-                          : lang_hooks.types.unsigned_type (type);
+                          ? signed_type_for (type)
+                          : unsigned_type_for (type);
              tree temp = fold_convert (ntype, TREE_OPERAND (t, 0));
              temp = fold_build2 (RSHIFT_EXPR, ntype, temp, op1);
              return fold_convert (type, temp);
@@ -1614,7 +1620,7 @@ int_binop_types_match_p (enum tree_code code, tree type1, tree type2)
    If NOTRUNC is nonzero, do not truncate the result to fit the data type.  */
 
 tree
-int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
+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;
@@ -2021,7 +2027,7 @@ size_diffop (tree arg0, tree arg1)
   else if (type == bitsizetype)
     ctype = sbitsizetype;
   else
-    ctype = lang_hooks.types.signed_type (type);
+    ctype = signed_type_for (type);
 
   /* If either operand is not a constant, do the conversions to the signed
      type and subtract.  The hardware will do the right thing with any
@@ -2204,6 +2210,40 @@ build_zero_vector (tree type)
   return build_vector (type, list);
 }
 
+/* Returns true, if ARG is convertible to TYPE using a NOP_EXPR.  */
+
+bool
+fold_convertible_p (const_tree type, const_tree arg)
+{
+  tree orig = TREE_TYPE (arg);
+
+  if (type == orig)
+    return true;
+
+  if (TREE_CODE (arg) == ERROR_MARK
+      || TREE_CODE (type) == ERROR_MARK
+      || TREE_CODE (orig) == ERROR_MARK)
+    return false;
+
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig))
+    return true;
+
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
+    case POINTER_TYPE: case REFERENCE_TYPE:
+    case OFFSET_TYPE:
+      if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig)
+         || TREE_CODE (orig) == OFFSET_TYPE)
+        return true;
+      return (TREE_CODE (orig) == VECTOR_TYPE
+             && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)));
+
+    default:
+      return TREE_CODE (type) == TREE_CODE (orig);
+    }
+}
+
 /* Convert expression ARG to type TYPE.  Used by the middle-end for
    simple conversions in preference to calling the front-end's convert.  */
 
@@ -2221,9 +2261,7 @@ fold_convert (tree type, tree arg)
       || TREE_CODE (orig) == ERROR_MARK)
     return error_mark_node;
 
-  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig)
-      || lang_hooks.types_compatible_p (TYPE_MAIN_VARIANT (type),
-                                       TYPE_MAIN_VARIANT (orig)))
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig))
     return fold_build1 (NOP_EXPR, type, arg);
 
   switch (TREE_CODE (type))
@@ -2706,7 +2744,7 @@ truth_value_p (enum tree_code code)
    to ensure that global memory is unchanged in between.  */
 
 int
-operand_equal_p (tree arg0, tree arg1, unsigned int flags)
+operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 {
   /* If either is ERROR_MARK, they aren't equal.  */
   if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK)
@@ -2886,9 +2924,13 @@ operand_equal_p (tree arg0, tree arg1, unsigned int flags)
 
        case ARRAY_REF:
        case ARRAY_RANGE_REF:
-         /* Operands 2 and 3 may be null.  */
+         /* Operands 2 and 3 may be null.
+            Compare the array index by value if it is constant first as we
+            may have different types but same value here.  */
          return (OP_SAME (0)
-                 && OP_SAME (1)
+                 && (tree_int_cst_equal (TREE_OPERAND (arg0, 1),
+                                         TREE_OPERAND (arg1, 1))
+                     || OP_SAME (1))
                  && OP_SAME_WITH_NULL (2)
                  && OP_SAME_WITH_NULL (3));
 
@@ -2929,10 +2971,18 @@ operand_equal_p (tree arg0, tree arg1, unsigned int flags)
                  && operand_equal_p (TREE_OPERAND (arg0, 1),
                                      TREE_OPERAND (arg1, 0), flags));
 
+       default:
+         return 0;
+       }
+
+    case tcc_vl_exp:
+      switch (TREE_CODE (arg0))
+       {
        case CALL_EXPR:
          /* If the CALL_EXPRs call different functions, then they
             clearly can not be equal.  */
-         if (!OP_SAME (0))
+         if (! operand_equal_p (CALL_EXPR_FN (arg0), CALL_EXPR_FN (arg1),
+                                flags))
            return 0;
 
          {
@@ -2945,25 +2995,22 @@ operand_equal_p (tree arg0, tree arg1, unsigned int flags)
              return 0;
          }
 
-         /* Now see if all the arguments are the same.  operand_equal_p
-            does not handle TREE_LIST, so we walk the operands here
-            feeding them to operand_equal_p.  */
-         arg0 = TREE_OPERAND (arg0, 1);
-         arg1 = TREE_OPERAND (arg1, 1);
-         while (arg0 && arg1)
-           {
-             if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1),
-                                    flags))
+         /* Now see if all the arguments are the same.  */
+         {
+           const_call_expr_arg_iterator iter0, iter1;
+           const_tree a0, a1;
+           for (a0 = first_const_call_expr_arg (arg0, &iter0),
+                  a1 = first_const_call_expr_arg (arg1, &iter1);
+                a0 && a1;
+                a0 = next_const_call_expr_arg (&iter0),
+                  a1 = next_const_call_expr_arg (&iter1))
+             if (! operand_equal_p (a0, a1, flags))
                return 0;
 
-             arg0 = TREE_CHAIN (arg0);
-             arg1 = TREE_CHAIN (arg1);
-           }
-
-         /* If we get here and both argument lists are exhausted
-            then the CALL_EXPRs are equal.  */
-         return ! (arg0 || arg1);
-
+           /* If we get here and both argument lists are exhausted
+              then the CALL_EXPRs are equal.  */
+           return ! (a0 || a1);
+         }
        default:
          return 0;
        }
@@ -3029,7 +3076,7 @@ operand_equal_for_comparison_p (tree arg0, tree arg1, tree other)
 
       /* Make sure shorter operand is extended the right way
         to match the longer operand.  */
-      primarg1 = fold_convert (lang_hooks.types.signed_or_unsigned_type
+      primarg1 = fold_convert (signed_or_unsigned_type_for
                               (unsignedp1, TREE_TYPE (primarg1)), primarg1);
 
       if (operand_equal_p (arg0, fold_convert (type, primarg1), 0))
@@ -3812,7 +3859,7 @@ all_ones_mask_p (tree mask, int size)
   unsigned int precision = TYPE_PRECISION (type);
   tree tmask;
 
-  tmask = build_int_cst_type (lang_hooks.types.signed_type (type), -1);
+  tmask = build_int_cst_type (signed_type_for (type), -1);
 
   return
     tree_int_cst_equal (mask,
@@ -4035,7 +4082,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
 
       if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
        {
-         if (TREE_CODE_LENGTH (code) > 0)
+         if (TREE_OPERAND_LENGTH (exp) > 0)
            arg0 = TREE_OPERAND (exp, 0);
          if (TREE_CODE_CLASS (code) == tcc_comparison
              || TREE_CODE_CLASS (code) == tcc_unary
@@ -4044,7 +4091,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
          if (TREE_CODE_CLASS (code) == tcc_binary
              || TREE_CODE_CLASS (code) == tcc_comparison
              || (TREE_CODE_CLASS (code) == tcc_expression
-                 && TREE_CODE_LENGTH (code) > 1))
+                 && TREE_OPERAND_LENGTH (exp) > 1))
            arg1 = TREE_OPERAND (exp, 1);
        }
 
@@ -4336,7 +4383,7 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
     {
       if (! TYPE_UNSIGNED (etype))
        {
-         etype = lang_hooks.types.unsigned_type (etype);
+         etype = unsigned_type_for (etype);
          high = fold_convert (etype, high);
          exp = fold_convert (etype, exp);
        }
@@ -4366,7 +4413,7 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
        {
          if (TYPE_UNSIGNED (etype))
            {
-             etype = lang_hooks.types.signed_type (etype);
+             etype = signed_type_for (etype);
              exp = fold_convert (etype, exp);
            }
          return fold_build2 (GT_EXPR, type, exp,
@@ -4404,7 +4451,7 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
 
       /* Check if (unsigned) INT_MAX + 1 == (unsigned) INT_MIN
         for the type in question, as we rely on this here.  */
-      utype = lang_hooks.types.unsigned_type (etype);
+      utype = unsigned_type_for (etype);
       maxv = fold_convert (utype, TYPE_MAX_VALUE (etype));
       maxv = range_binop (PLUS_EXPR, NULL_TREE, maxv, 1,
                          integer_one_node, 1);
@@ -4423,6 +4470,20 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
 
   value = const_binop (MINUS_EXPR, high, low, 0);
 
+
+  if (POINTER_TYPE_P (etype))
+    {
+      if (value != 0 && !TREE_OVERFLOW (value))
+       {
+         low = fold_convert (sizetype, low);
+         low = fold_build1 (NEGATE_EXPR, sizetype, low);
+          return build_range_check (type,
+                                   fold_build2 (POINTER_PLUS_EXPR, etype, exp, low),
+                                   1, build_int_cst (etype, 0), value);
+       }
+      return 0;
+    }
+
   if (value != 0 && !TREE_OVERFLOW (value))
     return build_range_check (type,
                              fold_build2 (MINUS_EXPR, etype, exp, low),
@@ -4533,13 +4594,24 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
        {
          low = range_successor (high1);
          high = high0;
-         in_p = (low != 0);
+         in_p = 1;
+         if (low == 0)
+           {
+             /* We are in the weird situation where high0 > high1 but
+                high1 has no successor.  Punt.  */
+             return 0;
+           }
        }
       else if (! subset || highequal)
        {
          low = low0;
          high = range_predecessor (low1);
-         in_p = (high != 0);
+         in_p = 1;
+         if (high == 0)
+           {
+             /* low0 < low1 but low1 has no predecessor.  Punt.  */
+             return 0;
+           }
        }
       else
        return 0;
@@ -4559,7 +4631,12 @@ merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
        {
          low = range_successor (high0);
          high = high1;
-         in_p = (low != 0);
+         in_p = 1;
+         if (low == 0)
+           {
+             /* high1 > high0 but high0 has no successor.  Punt.  */
+             return 0;
+           }
        }
     }
 
@@ -4724,7 +4801,7 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
       case GE_EXPR:
       case GT_EXPR:
        if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
-         arg1 = fold_convert (lang_hooks.types.signed_type
+         arg1 = fold_convert (signed_type_for
                               (TREE_TYPE (arg1)), arg1);
        tem = fold_build1 (ABS_EXPR, TREE_TYPE (arg1), arg1);
        return pedantic_non_lvalue (fold_convert (type, tem));
@@ -4735,7 +4812,7 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
       case LE_EXPR:
       case LT_EXPR:
        if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
-         arg1 = fold_convert (lang_hooks.types.signed_type
+         arg1 = fold_convert (signed_type_for
                               (TREE_TYPE (arg1)), arg1);
        tem = fold_build1 (ABS_EXPR, TREE_TYPE (arg1), arg1);
        return negate_expr (fold_convert (type, tem));
@@ -4881,7 +4958,9 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                             build_int_cst (type, 1), 0),
                                OEP_ONLY_CONST))
          return pedantic_non_lvalue (fold_build2 (MIN_EXPR,
-                                                  type, arg1, arg2));
+                                                  type,
+                                                  fold_convert (type, arg1),
+                                                  arg2));
        break;
 
       case LE_EXPR:
@@ -4893,7 +4972,9 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                             build_int_cst (type, 1), 0),
                                OEP_ONLY_CONST))
          return pedantic_non_lvalue (fold_build2 (MIN_EXPR,
-                                                  type, arg1, arg2));
+                                                  type,
+                                                  fold_convert (type, arg1),
+                                                  arg2));
        break;
 
       case GT_EXPR:
@@ -4905,7 +4986,9 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                             build_int_cst (type, 1), 0),
                                OEP_ONLY_CONST))
          return pedantic_non_lvalue (fold_build2 (MAX_EXPR,
-                                                  type, arg1, arg2));
+                                                  type,
+                                                  fold_convert (type, arg1),
+                                                  arg2));
        break;
 
       case GE_EXPR:
@@ -4917,7 +5000,9 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                             build_int_cst (type, 1), 0),
                                OEP_ONLY_CONST))
          return pedantic_non_lvalue (fold_build2 (MAX_EXPR,
-                                                  type, arg1, arg2));
+                                                  type,
+                                                  fold_convert (type, arg1),
+                                                  arg2));
        break;
       case NE_EXPR:
        break;
@@ -5043,7 +5128,7 @@ unextend (tree c, int p, int unsignedp, tree mask)
      zero or one, and the conversion to a signed type can never overflow.
      We could get an overflow if this conversion is done anywhere else.  */
   if (TYPE_UNSIGNED (type))
-    temp = fold_convert (lang_hooks.types.signed_type (type), temp);
+    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);
@@ -5677,6 +5762,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
       if ((COMPARISON_CLASS_P (op0)
           || UNARY_CLASS_P (op0)
           || BINARY_CLASS_P (op0)
+          || VL_EXP_CLASS_P (op0)
           || EXPRESSION_CLASS_P (op0))
          /* ... and is unsigned, and its type is smaller than ctype,
             then we cannot pass through as widening.  */
@@ -5714,7 +5800,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
          must avoid building ABS_EXPR itself as unsigned.  */
       if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (type))
         {
-          tree cstype = (*lang_hooks.types.signed_type) (ctype);
+          tree cstype = (*signed_type_for) (ctype);
           if ((t1 = extract_muldiv (op0, c, code, cstype, strict_overflow_p))
              != 0)
             {
@@ -5959,7 +6045,7 @@ constant_boolean_node (int value, tree type)
    offset is set to NULL_TREE.  Base will be canonicalized to
    something you can get the element type from using
    TREE_TYPE (TREE_TYPE (base)).  Offset will be the offset
-   in bytes to the base.  */
+   in bytes to the base in sizetype.  */
 
 static bool
 extract_array_ref (tree expr, tree *base, tree *offset)
@@ -5967,21 +6053,20 @@ extract_array_ref (tree expr, tree *base, tree *offset)
   /* One canonical form is a PLUS_EXPR with the first
      argument being an ADDR_EXPR with a possible NOP_EXPR
      attached.  */
-  if (TREE_CODE (expr) == PLUS_EXPR)
+  if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
     {
       tree op0 = TREE_OPERAND (expr, 0);
       tree inner_base, dummy1;
       /* Strip NOP_EXPRs here because the C frontends and/or
-        folders present us (int *)&x.a + 4B possibly.  */
+        folders present us (int *)&x.a p+ 4 possibly.  */
       STRIP_NOPS (op0);
       if (extract_array_ref (op0, &inner_base, &dummy1))
        {
          *base = inner_base;
-         if (dummy1 == NULL_TREE)
-           *offset = TREE_OPERAND (expr, 1);
-         else
-           *offset = fold_build2 (PLUS_EXPR, TREE_TYPE (expr),
-                                  dummy1, TREE_OPERAND (expr, 1));
+         *offset = fold_convert (sizetype, TREE_OPERAND (expr, 1));
+         if (dummy1 != NULL_TREE)
+           *offset = fold_build2 (PLUS_EXPR, sizetype,
+                                  dummy1, *offset);
          return true;
        }
     }
@@ -5999,6 +6084,7 @@ extract_array_ref (tree expr, tree *base, tree *offset)
          *base = TREE_OPERAND (op0, 0);
          *offset = fold_build2 (MULT_EXPR, TREE_TYPE (idx), idx,
                                 array_ref_element_size (op0)); 
+         *offset = fold_convert (sizetype, *offset);
        }
       else
        {
@@ -6151,7 +6237,7 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
 
   if (BUILTIN_SQRT_P (fcode))
     {
-      tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
+      tree arg = CALL_EXPR_ARG (arg0, 0);
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
 
       c = TREE_REAL_CST (arg1);
@@ -6525,7 +6611,7 @@ fold_single_bit_test_into_sign_test (enum tree_code code, tree arg0, tree arg1,
          && TYPE_PRECISION (TREE_TYPE (arg00))
             == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg00))))
        {
-         tree stype = lang_hooks.types.signed_type (TREE_TYPE (arg00));
+         tree stype = signed_type_for (TREE_TYPE (arg00));
          return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
                              result_type, fold_convert (stype, arg00),
                              build_int_cst (stype, 0));
@@ -6636,7 +6722,7 @@ reorder_operands_p (tree arg0, tree arg1)
    evaluate the operands in reverse order.  */
 
 bool
-tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
+tree_swap_operands_p (const_tree arg0, const_tree arg1, bool reorder)
 {
   STRIP_SIGN_NOPS (arg0);
   STRIP_SIGN_NOPS (arg1);
@@ -6668,11 +6754,6 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
       && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)))
     return 0;
 
-  if (DECL_P (arg1))
-    return 0;
-  if (DECL_P (arg0))
-    return 1;
-
   /* It is preferable to swap two SSA_NAME to ensure a canonical form
      for commutative and comparison operators.  Ensuring a canonical
      form allows the optimizers to find additional redundancies without
@@ -6682,6 +6763,18 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
       && SSA_NAME_VERSION (arg0) > SSA_NAME_VERSION (arg1))
     return 1;
 
+  /* Put SSA_NAMEs last.  */
+  if (TREE_CODE (arg1) == SSA_NAME)
+    return 0;
+  if (TREE_CODE (arg0) == SSA_NAME)
+    return 1;
+
+  /* Put variables last.  */
+  if (DECL_P (arg1))
+    return 0;
+  if (DECL_P (arg0))
+    return 1;
+
   return 0;
 }
 
@@ -6826,7 +6919,7 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
   return fold_build2 (code, type, arg0_inner, arg1);
 }
 
-/* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
+/* Tries to replace &a[idx] p+ s * delta with &a[idx + delta], if s is
    step of the array.  Reconstructs s and delta in the case of s * delta
    being an integer constant (and thus already folded).
    ADDR is the address. MULT is the multiplicative expression.
@@ -6834,7 +6927,7 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
    NULL_TREE is returned.  */
 
 static tree
-try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
+try_move_mult_to_index (tree addr, tree op1)
 {
   tree s, delta, step;
   tree ref = TREE_OPERAND (addr, 0), pref;
@@ -6842,6 +6935,9 @@ try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
   tree itype;
   bool mdim = false;
 
+  /*  Strip the nops that might be added when converting op1 to sizetype. */
+  STRIP_NOPS (op1);
+
   /* Canonicalize op1 into a possibly non-constant delta
      and an INTEGER_CST s.  */
   if (TREE_CODE (op1) == MULT_EXPR)
@@ -6918,7 +7014,7 @@ try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
                  || TREE_CODE (TYPE_MAX_VALUE (itype)) != INTEGER_CST)
                continue;
 
-             tmp = fold_binary (code, itype,
+             tmp = fold_binary (PLUS_EXPR, itype,
                                 fold_convert (itype,
                                               TREE_OPERAND (ref, 1)),
                                 fold_convert (itype, delta));
@@ -6951,7 +7047,7 @@ try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
       pos = TREE_OPERAND (pos, 0);
     }
 
-  TREE_OPERAND (pos, 1) = fold_build2 (code, itype,
+  TREE_OPERAND (pos, 1) = fold_build2 (PLUS_EXPR, itype,
                                       fold_convert (itype,
                                                     TREE_OPERAND (pos, 1)),
                                       fold_convert (itype, delta));
@@ -6997,9 +7093,18 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
   if (TREE_TYPE (a1) != typea)
     return NULL_TREE;
 
-  diff = fold_build2 (MINUS_EXPR, typea, a1, a);
-  if (!integer_onep (diff))
-    return NULL_TREE;
+  if (POINTER_TYPE_P (typea))
+    {
+      /* Convert the pointer types into integer before taking the difference.  */
+      tree ta = fold_convert (ssizetype, a);
+      tree ta1 = fold_convert (ssizetype, a1);
+      diff = fold_binary (MINUS_EXPR, ssizetype, ta1, ta);
+    }
+  else
+   diff = fold_binary (MINUS_EXPR, typea, a1, a);
+
+  if (!diff || !integer_onep (diff))
+   return NULL_TREE;
 
   return fold_build2 (GE_EXPR, type, a, y);
 }
@@ -7024,6 +7129,11 @@ fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
       arg00 = TREE_OPERAND (arg0, 0);
       arg01 = TREE_OPERAND (arg0, 1);
     }
+  else if (TREE_CODE (arg0) == INTEGER_CST)
+    {
+      arg00 = build_one_cst (type);
+      arg01 = arg0;
+    }
   else
     {
       arg00 = arg0;
@@ -7034,6 +7144,11 @@ fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
       arg10 = TREE_OPERAND (arg1, 0);
       arg11 = TREE_OPERAND (arg1, 1);
     }
+  else if (TREE_CODE (arg1) == INTEGER_CST)
+    {
+      arg10 = build_one_cst (type);
+      arg11 = arg1;
+    }
   else
     {
       arg10 = arg1;
@@ -7102,7 +7217,7 @@ fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
    upon failure.  */
 
 static int
-native_encode_int (tree expr, unsigned char *ptr, int len)
+native_encode_int (const_tree expr, unsigned char *ptr, int len)
 {
   tree type = TREE_TYPE (expr);
   int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
@@ -7147,11 +7262,11 @@ native_encode_int (tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_real (tree expr, unsigned char *ptr, int len)
+native_encode_real (const_tree expr, unsigned char *ptr, int len)
 {
   tree type = TREE_TYPE (expr);
   int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
-  int byte, offset, word, words;
+  int byte, offset, word, words, bitpos;
   unsigned char value;
 
   /* There are always 32 bits in each long, no matter the size of
@@ -7161,19 +7276,20 @@ native_encode_real (tree expr, unsigned char *ptr, int len)
 
   if (total_bytes > len)
     return 0;
-  words = total_bytes / UNITS_PER_WORD;
+  words = 32 / UNITS_PER_WORD;
 
   real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
 
-  for (byte = 0; byte < total_bytes; byte++)
+  for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT;
+       bitpos += BITS_PER_UNIT)
     {
-      int bitpos = byte * BITS_PER_UNIT;
+      byte = (bitpos / BITS_PER_UNIT) & 3;
       value = (unsigned char) (tmp[bitpos / 32] >> (bitpos & 31));
 
-      if (total_bytes > UNITS_PER_WORD)
+      if (UNITS_PER_WORD < 4)
        {
          word = byte / UNITS_PER_WORD;
-         if (FLOAT_WORDS_BIG_ENDIAN)
+         if (WORDS_BIG_ENDIAN)
            word = (words - 1) - word;
          offset = word * UNITS_PER_WORD;
          if (BYTES_BIG_ENDIAN)
@@ -7182,8 +7298,8 @@ native_encode_real (tree expr, unsigned char *ptr, int len)
            offset += byte % UNITS_PER_WORD;
        }
       else
-       offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
-      ptr[offset] = value;
+       offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
+      ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)] = value;
     }
   return total_bytes;
 }
@@ -7194,7 +7310,7 @@ native_encode_real (tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_complex (tree expr, unsigned char *ptr, int len)
+native_encode_complex (const_tree expr, unsigned char *ptr, int len)
 {
   int rsize, isize;
   tree part;
@@ -7217,7 +7333,7 @@ native_encode_complex (tree expr, unsigned char *ptr, int len)
    upon failure.  */
 
 static int
-native_encode_vector (tree expr, unsigned char *ptr, int len)
+native_encode_vector (const_tree expr, unsigned char *ptr, int len)
 {
   int i, size, offset, count;
   tree itype, elem, elements;
@@ -7259,8 +7375,8 @@ native_encode_vector (tree expr, unsigned char *ptr, int len)
    buffer PTR of length LEN bytes.  Return the number of bytes
    placed in the buffer, or zero upon failure.  */
 
-static int
-native_encode_expr (tree expr, unsigned char *ptr, int len)
+int
+native_encode_expr (const_tree expr, unsigned char *ptr, int len)
 {
   switch (TREE_CODE (expr))
     {
@@ -7287,7 +7403,7 @@ native_encode_expr (tree expr, unsigned char *ptr, int len)
    If the buffer cannot be interpreted, return NULL_TREE.  */
 
 static tree
-native_interpret_int (tree type, unsigned char *ptr, int len)
+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;
@@ -7335,11 +7451,11 @@ native_interpret_int (tree type, unsigned char *ptr, int len)
    If the buffer cannot be interpreted, return NULL_TREE.  */
 
 static tree
-native_interpret_real (tree type, unsigned char *ptr, int len)
+native_interpret_real (tree type, const unsigned char *ptr, int len)
 {
   enum machine_mode mode = TYPE_MODE (type);
   int total_bytes = GET_MODE_SIZE (mode);
-  int byte, offset, word, words;
+  int byte, offset, word, words, bitpos;
   unsigned char value;
   /* There are always 32 bits in each long, no matter the size of
      the hosts long.  We handle floating point representations with
@@ -7350,16 +7466,17 @@ native_interpret_real (tree type, unsigned char *ptr, int len)
   total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
   if (total_bytes > len || total_bytes > 24)
     return NULL_TREE;
-  words = total_bytes / UNITS_PER_WORD;
+  words = 32 / UNITS_PER_WORD;
 
   memset (tmp, 0, sizeof (tmp));
-  for (byte = 0; byte < total_bytes; byte++)
+  for (bitpos = 0; bitpos < total_bytes * BITS_PER_UNIT;
+       bitpos += BITS_PER_UNIT)
     {
-      int bitpos = byte * BITS_PER_UNIT;
-      if (total_bytes > UNITS_PER_WORD)
+      byte = (bitpos / BITS_PER_UNIT) & 3;
+      if (UNITS_PER_WORD < 4)
        {
          word = byte / UNITS_PER_WORD;
-         if (FLOAT_WORDS_BIG_ENDIAN)
+         if (WORDS_BIG_ENDIAN)
            word = (words - 1) - word;
          offset = word * UNITS_PER_WORD;
          if (BYTES_BIG_ENDIAN)
@@ -7368,8 +7485,8 @@ native_interpret_real (tree type, unsigned char *ptr, int len)
            offset += byte % UNITS_PER_WORD;
        }
       else
-       offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
-      value = ptr[offset];
+       offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
+      value = ptr[offset + ((bitpos / BITS_PER_UNIT) & ~3)];
 
       tmp[bitpos / 32] |= (unsigned long)value << (bitpos & 31);
     }
@@ -7384,7 +7501,7 @@ native_interpret_real (tree type, unsigned char *ptr, int len)
    If the buffer cannot be interpreted, return NULL_TREE.  */
 
 static tree
-native_interpret_complex (tree type, unsigned char *ptr, int len)
+native_interpret_complex (tree type, const unsigned char *ptr, int len)
 {
   tree etype, rpart, ipart;
   int size;
@@ -7408,7 +7525,7 @@ native_interpret_complex (tree type, unsigned char *ptr, int len)
    If the buffer cannot be interpreted, return NULL_TREE.  */
 
 static tree
-native_interpret_vector (tree type, unsigned char *ptr, int len)
+native_interpret_vector (tree type, const unsigned char *ptr, int len)
 {
   tree etype, elem, elements;
   int i, size, count;
@@ -7437,8 +7554,8 @@ native_interpret_vector (tree type, unsigned char *ptr, int len)
    we return a REAL_CST, etc...  If the buffer cannot be interpreted,
    return NULL_TREE.  */
 
-static tree
-native_interpret_expr (tree type, unsigned char *ptr, int len)
+tree
+native_interpret_expr (tree type, const unsigned char *ptr, int len)
 {
   switch (TREE_CODE (type))
     {
@@ -7484,6 +7601,77 @@ fold_view_convert_expr (tree type, tree expr)
   return native_interpret_expr (type, buffer, len);
 }
 
+/* Build an expression for the address of T.  Folds away INDIRECT_REF
+   to avoid confusing the gimplify process.  When IN_FOLD is true
+   avoid modifications of T.  */
+
+static tree
+build_fold_addr_expr_with_type_1 (tree t, tree ptrtype, bool in_fold)
+{
+  /* The size of the object is not relevant when talking about its address.  */
+  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)
+    {
+      t = TREE_OPERAND (t, 0);
+
+      if (TREE_TYPE (t) != ptrtype)
+       t = build1 (NOP_EXPR, ptrtype, t);
+    }
+  else if (!in_fold)
+    {
+      tree base = t;
+
+      while (handled_component_p (base))
+       base = TREE_OPERAND (base, 0);
+
+      if (DECL_P (base))
+       TREE_ADDRESSABLE (base) = 1;
+
+      t = build1 (ADDR_EXPR, ptrtype, t);
+    }
+  else
+    t = build1 (ADDR_EXPR, ptrtype, t);
+
+  return t;
+}
+
+/* Build an expression for the address of T with type PTRTYPE.  This
+   function modifies the input parameter 'T' by sometimes setting the
+   TREE_ADDRESSABLE flag.  */
+
+tree
+build_fold_addr_expr_with_type (tree t, tree ptrtype)
+{
+  return build_fold_addr_expr_with_type_1 (t, ptrtype, false);
+}
+
+/* Build an expression for the address of T.  This function modifies
+   the input parameter 'T' by sometimes setting the TREE_ADDRESSABLE
+   flag.  When called from fold functions, use fold_addr_expr instead.  */
+
+tree
+build_fold_addr_expr (tree t)
+{
+  return build_fold_addr_expr_with_type_1 (t, 
+                                          build_pointer_type (TREE_TYPE (t)),
+                                          false);
+}
+
+/* Same as build_fold_addr_expr, builds an expression for the address
+   of T, but avoids touching the input node 't'.  Fold functions
+   should use this version.  */
+
+static tree
+fold_addr_expr (tree t)
+{
+  tree ptrtype = build_pointer_type (TREE_TYPE (t));
+
+  return build_fold_addr_expr_with_type_1 (t, ptrtype, true);
+}
 
 /* Fold a unary expression of code CODE and type TYPE with operand
    OP0.  Return the folded expression if folding is successful.
@@ -7719,7 +7907,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
          if (! offset && bitpos == 0
              && TYPE_MAIN_VARIANT (TREE_TYPE (type))
                  == TYPE_MAIN_VARIANT (TREE_TYPE (base)))
-           return fold_convert (type, build_fold_addr_expr (base));
+           return fold_convert (type, fold_addr_expr (base));
         }
 
       if ((TREE_CODE (op0) == MODIFY_EXPR
@@ -7772,7 +7960,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
                  && (LOAD_EXTEND_OP (TYPE_MODE (TREE_TYPE (and0)))
                      == ZERO_EXTEND))
                {
-                 tree uns = lang_hooks.types.unsigned_type (TREE_TYPE (and0));
+                 tree uns = unsigned_type_for (TREE_TYPE (and0));
                  and0 = fold_convert (uns, and0);
                  and1 = fold_convert (uns, and1);
                }
@@ -7788,28 +7976,24 @@ fold_unary (enum tree_code code, tree type, tree op0)
            }
        }
 
-      /* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and
-        T2 being pointers to types of the same size.  */
+      /* Convert (T1)(X p+ Y) into ((T1)X p+ Y), for pointer type,
+         when one of the new casts will fold away. Conservatively we assume
+        that this happens when X or Y is NOP_EXPR or Y is INTEGER_CST. */
       if (POINTER_TYPE_P (type)
-         && BINARY_CLASS_P (arg0)
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
-         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+         && TREE_CODE (arg0) == POINTER_PLUS_EXPR
+         && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+             || TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
+             || TREE_CODE (TREE_OPERAND (arg0, 1)) == NOP_EXPR))
        {
          tree arg00 = TREE_OPERAND (arg0, 0);
-         tree t0 = type;
-         tree t1 = TREE_TYPE (arg00);
-         tree tt0 = TREE_TYPE (t0);
-         tree tt1 = TREE_TYPE (t1);
-         tree s0 = TYPE_SIZE (tt0);
-         tree s1 = TYPE_SIZE (tt1);
+         tree arg01 = TREE_OPERAND (arg0, 1);
 
-         if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST))
-           return build2 (TREE_CODE (arg0), t0, fold_convert (t0, arg00),
-                          TREE_OPERAND (arg0, 1));
+         return fold_build2 (TREE_CODE (arg0), type, fold_convert (type, arg00),
+                             fold_convert (sizetype, arg01));
        }
 
       /* Convert (T1)(~(T2)X) into ~(T1)X if T1 and T2 are integral types
-        of the same precision, and X is a integer type not narrower than
+        of the same precision, and X is an integer type not narrower than
         types T1 or T2, i.e. the cast (T2)X isn't an extension.  */
       if (INTEGRAL_TYPE_P (type)
          && TREE_CODE (op0) == BIT_NOT_EXPR
@@ -7824,7 +8008,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
            return fold_build1 (BIT_NOT_EXPR, type, fold_convert (type, tem));
        }
 
-      tem = fold_convert_const (code, type, arg0);
+      tem = fold_convert_const (code, type, op0);
       return tem ? tem : NULL_TREE;
 
     case VIEW_CONVERT_EXPR:
@@ -7970,8 +8154,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
              CASE_FLT_FN (BUILT_IN_CEXPI):
                fn = mathfn_built_in (type, BUILT_IN_COS);
                if (fn)
-                 return build_function_call_expr (fn,
-                                                  TREE_OPERAND (arg0, 1));
+                 return build_call_expr (fn, 1, CALL_EXPR_ARG (arg0, 0));
                break;
 
              default:
@@ -8013,8 +8196,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
              CASE_FLT_FN (BUILT_IN_CEXPI):
                fn = mathfn_built_in (type, BUILT_IN_SIN);
                if (fn)
-                 return build_function_call_expr (fn,
-                                                  TREE_OPERAND (arg0, 1));
+                 return build_call_expr (fn, 1, CALL_EXPR_ARG (arg0, 0));
                break;
 
              default:
@@ -8522,7 +8704,7 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
       return fold_build2 (cmp_code, type, variable1, const2);
     }
 
-  tem = maybe_canonicalize_comparison (code, type, arg0, arg1);
+  tem = maybe_canonicalize_comparison (code, type, op0, op1);
   if (tem)
     return tem;
 
@@ -8625,69 +8807,6 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
        }
     }
 
-  /* Convert foo++ == CONST into ++foo == CONST + INCR.  */
-  if (TREE_CONSTANT (arg1)
-      && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
-         || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
-      /* This optimization is invalid for ordered comparisons
-         if CONST+INCR overflows or if foo+incr might overflow.
-        This optimization is invalid for floating point due to rounding.
-        For pointer types we assume overflow doesn't happen.  */
-      && (POINTER_TYPE_P (TREE_TYPE (arg0))
-         || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
-             && (code == EQ_EXPR || code == NE_EXPR))))
-    {
-      tree varop, newconst;
-
-      if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
-       {
-         newconst = fold_build2 (PLUS_EXPR, TREE_TYPE (arg0),
-                                 arg1, TREE_OPERAND (arg0, 1));
-         varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0),
-                         TREE_OPERAND (arg0, 0),
-                         TREE_OPERAND (arg0, 1));
-       }
-      else
-       {
-         newconst = fold_build2 (MINUS_EXPR, TREE_TYPE (arg0),
-                                 arg1, TREE_OPERAND (arg0, 1));
-         varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0),
-                         TREE_OPERAND (arg0, 0),
-                         TREE_OPERAND (arg0, 1));
-       }
-
-
-      /* If VAROP is a reference to a bitfield, we must mask
-        the constant by the width of the field.  */
-      if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
-         && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
-         && host_integerp (DECL_SIZE (TREE_OPERAND
-                                        (TREE_OPERAND (varop, 0), 1)), 1))
-       {
-         tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
-         HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
-         tree folded_compare, shift;
-
-         /* First check whether the comparison would come out
-            always the same.  If we don't do that we would
-            change the meaning with the masking.  */
-         folded_compare = fold_build2 (code, type,
-                                       TREE_OPERAND (varop, 0), arg1);
-         if (TREE_CODE (folded_compare) == INTEGER_CST)
-           return omit_one_operand (type, folded_compare, varop);
-
-         shift = build_int_cst (NULL_TREE,
-                                TYPE_PRECISION (TREE_TYPE (varop)) - size);
-         shift = fold_convert (TREE_TYPE (varop), shift);
-         newconst = fold_build2 (LSHIFT_EXPR, TREE_TYPE (varop),
-                                 newconst, shift);
-         newconst = fold_build2 (RSHIFT_EXPR, TREE_TYPE (varop),
-                                 newconst, shift);
-       }
-
-      return fold_build2 (code, type, varop, newconst);
-    }
-
   if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
       && (TREE_CODE (arg0) == NOP_EXPR
          || TREE_CODE (arg0) == CONVERT_EXPR))
@@ -8865,8 +8984,8 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
          tree op0 = TREE_OPERAND (cref0, 0);
          tree op1 = TREE_OPERAND (cref1, 0);
          return fold_build2 (code, type,
-                             build_fold_addr_expr (op0),
-                             build_fold_addr_expr (op1));
+                             fold_addr_expr (op0),
+                             fold_addr_expr (op1));
        }
     }
 
@@ -8888,16 +9007,23 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
   /* Fold ~X op ~Y as Y op X.  */
   if (TREE_CODE (arg0) == BIT_NOT_EXPR
       && TREE_CODE (arg1) == BIT_NOT_EXPR)
-    return fold_build2 (code, type,
-                       TREE_OPERAND (arg1, 0),
-                       TREE_OPERAND (arg0, 0));
+    {
+      tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
+      return fold_build2 (code, type,
+                         fold_convert (cmp_type, TREE_OPERAND (arg1, 0)),
+                         TREE_OPERAND (arg0, 0));
+    }
 
   /* Fold ~X op C as X op' ~C, where op' is the swapped comparison.  */
   if (TREE_CODE (arg0) == BIT_NOT_EXPR
       && TREE_CODE (arg1) == INTEGER_CST)
-    return fold_build2 (swap_tree_comparison (code), type,
-                       TREE_OPERAND (arg0, 0),
-                       fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1));
+    {
+      tree cmp_type = TREE_TYPE (TREE_OPERAND (arg0, 0));
+      return fold_build2 (swap_tree_comparison (code), type,
+                         TREE_OPERAND (arg0, 0),
+                         fold_build1 (BIT_NOT_EXPR, cmp_type,
+                                      fold_convert (cmp_type, arg1)));
+    }
 
   return NULL_TREE;
 }
@@ -9086,7 +9212,68 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 
   switch (code)
     {
+    case POINTER_PLUS_EXPR:
+      /* 0 +p index -> (type)index */
+      if (integer_zerop (arg0))
+       return non_lvalue (fold_convert (type, arg1));
+
+      /* PTR +p 0 -> PTR */
+      if (integer_zerop (arg1))
+       return non_lvalue (fold_convert (type, arg0));
+
+      /* INT +p INT -> (PTR)(INT + INT).  Stripping types allows for this. */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+          && INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
+        return fold_convert (type, fold_build2 (PLUS_EXPR, sizetype,
+                                               fold_convert (sizetype, arg1),
+                                               fold_convert (sizetype, arg0)));
+
+      /* index +p PTR -> PTR +p index */
+      if (POINTER_TYPE_P (TREE_TYPE (arg1))
+         && INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
+        return fold_build2 (POINTER_PLUS_EXPR, type,
+                           fold_convert (type, arg1), fold_convert (sizetype, arg0));
+
+      /* (PTR +p B) +p A -> PTR +p (B + A) */
+      if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
+       {
+         tree inner;
+         tree arg01 = fold_convert (sizetype, TREE_OPERAND (arg0, 1));
+         tree arg00 = TREE_OPERAND (arg0, 0);
+         inner = fold_build2 (PLUS_EXPR, sizetype, arg01, fold_convert (sizetype, arg1));
+         return fold_build2 (POINTER_PLUS_EXPR, type, arg00, inner);
+       }
+
+      /* PTR_CST +p CST -> CST1 */
+      if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+       return fold_build2 (PLUS_EXPR, type, arg0, fold_convert (type, arg1));
+
+     /* Try replacing &a[i1] +p c * i2 with &a[i1 + i2], if c is step
+       of the array.  Loop optimizer sometimes produce this type of
+       expressions.  */
+      if (TREE_CODE (arg0) == ADDR_EXPR)
+       {
+         tem = try_move_mult_to_index (arg0, fold_convert (sizetype, arg1));
+         if (tem)
+           return fold_convert (type, tem);
+       }
+
+      return NULL_TREE;
     case PLUS_EXPR:
+      /* PTR + INT -> (INT)(PTR p+ INT) */
+      if (POINTER_TYPE_P (TREE_TYPE (arg0))
+         && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
+       return fold_convert (type, fold_build2 (POINTER_PLUS_EXPR,
+                                               TREE_TYPE (arg0),
+                                               arg0,
+                                               fold_convert (sizetype, arg1)));
+      /* INT + PTR -> (INT)(PTR p+ INT) */
+      if (POINTER_TYPE_P (TREE_TYPE (arg1))
+         && INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
+       return fold_convert (type, fold_build2 (POINTER_PLUS_EXPR,
+                                               TREE_TYPE (arg1),
+                                               arg1,
+                                               fold_convert (sizetype, arg0)));
       /* A + (-B) -> A - B */
       if (TREE_CODE (arg1) == NEGATE_EXPR)
        return fold_build2 (MINUS_EXPR, type,
@@ -9098,11 +9285,42 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        return fold_build2 (MINUS_EXPR, type,
                            fold_convert (type, arg1),
                            fold_convert (type, TREE_OPERAND (arg0, 0)));
-      /* Convert ~A + 1 to -A.  */
-      if (INTEGRAL_TYPE_P (type)
-         && TREE_CODE (arg0) == BIT_NOT_EXPR
-         && integer_onep (arg1))
-       return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
+
+      if (INTEGRAL_TYPE_P (type))
+       {
+         /* Convert ~A + 1 to -A.  */
+         if (TREE_CODE (arg0) == BIT_NOT_EXPR
+             && integer_onep (arg1))
+           return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
+
+         /* ~X + X is -1.  */
+         if (TREE_CODE (arg0) == BIT_NOT_EXPR
+             && !TYPE_OVERFLOW_TRAPS (type))
+           {
+             tree tem = TREE_OPERAND (arg0, 0);
+
+             STRIP_NOPS (tem);
+             if (operand_equal_p (tem, arg1, 0))
+               {
+                 t1 = build_int_cst_type (type, -1);
+                 return omit_one_operand (type, t1, arg1);
+               }
+           }
+
+         /* X + ~X is -1.  */
+         if (TREE_CODE (arg1) == BIT_NOT_EXPR
+             && !TYPE_OVERFLOW_TRAPS (type))
+           {
+             tree tem = TREE_OPERAND (arg1, 0);
+
+             STRIP_NOPS (tem);
+             if (operand_equal_p (arg0, tem, 0))
+               {
+                 t1 = build_int_cst_type (type, -1);
+                 return omit_one_operand (type, t1, arg0);
+               }
+           }
+       }
 
       /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the
         same or one.  */
@@ -9120,24 +9338,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          if (integer_zerop (arg1))
            return non_lvalue (fold_convert (type, arg0));
 
-         /* ~X + X is -1.  */
-         if (TREE_CODE (arg0) == BIT_NOT_EXPR
-             && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
-             && !TYPE_OVERFLOW_TRAPS (type))
-           {
-             t1 = build_int_cst_type (type, -1);
-             return omit_one_operand (type, t1, arg1);
-           }
-
-         /* X + ~X is -1.  */
-         if (TREE_CODE (arg1) == BIT_NOT_EXPR
-             && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)
-             && !TYPE_OVERFLOW_TRAPS (type))
-           {
-             t1 = build_int_cst_type (type, -1);
-             return omit_one_operand (type, t1, arg0);
-         }
-
          /* If we are adding two BIT_AND_EXPR's, both of which are and'ing
             with a constant, and the two constants have no bits in common,
             we should treat this as a BIT_IOR_EXPR since this may produce more
@@ -9193,22 +9393,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                                 fold_convert (type,
                                                               parg1)));
            }
-
-         /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
-            of the array.  Loop optimizer sometimes produce this type of
-            expressions.  */
-         if (TREE_CODE (arg0) == ADDR_EXPR)
-           {
-             tem = try_move_mult_to_index (PLUS_EXPR, arg0, arg1);
-             if (tem)
-               return fold_convert (type, tem);
-           }
-         else if (TREE_CODE (arg1) == ADDR_EXPR)
-           {
-             tem = try_move_mult_to_index (PLUS_EXPR, arg1, arg0);
-             if (tem)
-               return fold_convert (type, tem);
-           }
        }
       else
        {
@@ -9391,6 +9575,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        {
          tree var0, con0, lit0, minus_lit0;
          tree var1, con1, lit1, minus_lit1;
+         bool ok = true;
 
          /* Split both trees into variables, constants, and literals.  Then
             associate each group together, the constants with literals,
@@ -9401,12 +9586,32 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          var1 = split_tree (arg1, code, &con1, &lit1, &minus_lit1,
                             code == MINUS_EXPR);
 
+         /* With undefined overflow we can only associate constants
+            with one variable.  */
+         if ((POINTER_TYPE_P (type)
+              || (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type)))
+             && var0 && var1)
+           {
+             tree tmp0 = var0;
+             tree tmp1 = var1;
+
+             if (TREE_CODE (tmp0) == NEGATE_EXPR)
+               tmp0 = TREE_OPERAND (tmp0, 0);
+             if (TREE_CODE (tmp1) == NEGATE_EXPR)
+               tmp1 = TREE_OPERAND (tmp1, 0);
+             /* The only case we can still associate with two variables
+                is if they are the same, modulo negation.  */
+             if (!operand_equal_p (tmp0, tmp1, 0))
+               ok = false;
+           }
+
          /* Only do something if we found more than two objects.  Otherwise,
             nothing has changed and we risk infinite recursion.  */
-         if (2 < ((var0 != 0) + (var1 != 0)
-                  + (con0 != 0) + (con1 != 0)
-                  + (lit0 != 0) + (lit1 != 0)
-                  + (minus_lit0 != 0) + (minus_lit1 != 0)))
+         if (ok
+             && (2 < ((var0 != 0) + (var1 != 0)
+                      + (con0 != 0) + (con1 != 0)
+                      + (lit0 != 0) + (lit1 != 0)
+                      + (minus_lit0 != 0) + (minus_lit1 != 0))))
            {
              /* Recombine MINUS_EXPR operands by using PLUS_EXPR.  */
              if (code == MINUS_EXPR)
@@ -9464,6 +9669,31 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       return NULL_TREE;
 
     case MINUS_EXPR:
+      /* Pointer simplifications for subtraction, simple reassociations. */
+      if (POINTER_TYPE_P (TREE_TYPE (arg1)) && POINTER_TYPE_P (TREE_TYPE (arg0)))
+       {
+         /* (PTR0 p+ A) - (PTR1 p+ B) -> (PTR0 - PTR1) + (A - B) */
+         if (TREE_CODE (arg0) == POINTER_PLUS_EXPR
+             && TREE_CODE (arg1) == POINTER_PLUS_EXPR)
+           {
+             tree arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
+             tree arg01 = fold_convert (type, TREE_OPERAND (arg0, 1));
+             tree arg10 = fold_convert (type, TREE_OPERAND (arg1, 0));
+             tree arg11 = fold_convert (type, TREE_OPERAND (arg1, 1));
+             return fold_build2 (PLUS_EXPR, type,
+                                 fold_build2 (MINUS_EXPR, type, arg00, arg10),
+                                 fold_build2 (MINUS_EXPR, type, arg01, arg11));
+           }
+         /* (PTR0 p+ A) - PTR1 -> (PTR0 - PTR1) + A, assuming PTR0 - PTR1 simplifies. */
+         else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
+           {
+             tree arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
+             tree arg01 = fold_convert (type, TREE_OPERAND (arg0, 1));
+             tree tmp = fold_binary (MINUS_EXPR, type, arg00, fold_convert (type, arg1));
+             if (tmp)
+               return fold_build2 (PLUS_EXPR, type, tmp, arg01);
+           }
+       }
       /* A - (-B) -> A + B */
       if (TREE_CODE (arg1) == NEGATE_EXPR)
        return fold_build2 (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0));
@@ -9584,7 +9814,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
         Also note that operand_equal_p is always false if an operand
         is volatile.  */
 
-      if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
+      if ((! FLOAT_TYPE_P (type)
+          || (flag_unsafe_math_optimizations
+              && !HONOR_NANS (TYPE_MODE (type))
+              && !HONOR_INFINITIES (TYPE_MODE (type))))
          && operand_equal_p (arg0, arg1, 0))
        return fold_convert (type, integer_zero_node);
 
@@ -9630,16 +9863,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            }
        }
 
-      /* Try replacing &a[i1] - c * i2 with &a[i1 - i2], if c is step
-        of the array.  Loop optimizer sometimes produce this type of
-        expressions.  */
-      if (TREE_CODE (arg0) == ADDR_EXPR)
-       {
-         tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1);
-         if (tem)
-           return fold_convert (type, tem);
-       }
-
       if (flag_unsafe_math_optimizations
          && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
          && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
@@ -9807,9 +10030,9 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              /* Optimizations of root(...)*root(...).  */
              if (fcode0 == fcode1 && BUILTIN_ROOT_P (fcode0))
                {
-                 tree rootfn, arg, arglist;
-                 tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-                 tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+                 tree rootfn, arg;
+                 tree arg00 = CALL_EXPR_ARG (arg0, 0);
+                 tree arg10 = CALL_EXPR_ARG (arg1, 0);
 
                  /* Optimize sqrt(x)*sqrt(x) as x.  */
                  if (BUILTIN_SQRT_P (fcode0)
@@ -9818,21 +10041,19 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                    return arg00;
 
                  /* Optimize root(x)*root(y) as root(x*y).  */
-                 rootfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                 rootfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
                  arg = fold_build2 (MULT_EXPR, type, arg00, arg10);
-                 arglist = build_tree_list (NULL_TREE, arg);
-                 return build_function_call_expr (rootfn, arglist);
+                 return build_call_expr (rootfn, 1, arg);
                }
 
              /* Optimize expN(x)*expN(y) as expN(x+y).  */
              if (fcode0 == fcode1 && BUILTIN_EXPONENT_P (fcode0))
                {
-                 tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                 tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
                  tree arg = fold_build2 (PLUS_EXPR, type,
-                                         TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                         TREE_VALUE (TREE_OPERAND (arg1, 1)));
-                 tree arglist = build_tree_list (NULL_TREE, arg);
-                 return build_function_call_expr (expfn, arglist);
+                                         CALL_EXPR_ARG (arg0, 0),
+                                         CALL_EXPR_ARG (arg1, 0));
+                 return build_call_expr (expfn, 1, arg);
                }
 
              /* Optimizations of pow(...)*pow(...).  */
@@ -9840,33 +10061,25 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  || (fcode0 == BUILT_IN_POWF && fcode1 == BUILT_IN_POWF)
                  || (fcode0 == BUILT_IN_POWL && fcode1 == BUILT_IN_POWL))
                {
-                 tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-                 tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
-                                                                    1)));
-                 tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
-                 tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
-                                                                    1)));
+                 tree arg00 = CALL_EXPR_ARG (arg0, 0);
+                 tree arg01 = CALL_EXPR_ARG (arg0, 1);
+                 tree arg10 = CALL_EXPR_ARG (arg1, 0);
+                 tree arg11 = CALL_EXPR_ARG (arg1, 1);
 
                  /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y).  */
                  if (operand_equal_p (arg01, arg11, 0))
                    {
-                     tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                     tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
                      tree arg = fold_build2 (MULT_EXPR, type, arg00, arg10);
-                     tree arglist = tree_cons (NULL_TREE, arg,
-                                               build_tree_list (NULL_TREE,
-                                                                arg01));
-                     return build_function_call_expr (powfn, arglist);
+                     return build_call_expr (powfn, 2, arg, arg01);
                    }
 
                  /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z).  */
                  if (operand_equal_p (arg00, arg10, 0))
                    {
-                     tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                     tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
                      tree arg = fold_build2 (PLUS_EXPR, type, arg01, arg11);
-                     tree arglist = tree_cons (NULL_TREE, arg00,
-                                               build_tree_list (NULL_TREE,
-                                                                arg));
-                     return build_function_call_expr (powfn, arglist);
+                     return build_call_expr (powfn, 2, arg00, arg);
                    }
                }
 
@@ -9877,14 +10090,13 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                   || (fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_TAN)
                   || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_TANF)
                   || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_TANL))
-                 && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                     TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
+                 && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
+                                     CALL_EXPR_ARG (arg1, 0), 0))
                {
                  tree sinfn = mathfn_built_in (type, BUILT_IN_SIN);
 
                  if (sinfn != NULL_TREE)
-                   return build_function_call_expr (sinfn,
-                                                    TREE_OPERAND (arg0, 1));
+                   return build_call_expr (sinfn, 1, CALL_EXPR_ARG (arg0, 0));
                }
 
              /* Optimize x*pow(x,c) as pow(x,c+1).  */
@@ -9892,23 +10104,20 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  || fcode1 == BUILT_IN_POWF
                  || fcode1 == BUILT_IN_POWL)
                {
-                 tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
-                 tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
-                                                                    1)));
+                 tree arg10 = CALL_EXPR_ARG (arg1, 0);
+                 tree arg11 = CALL_EXPR_ARG (arg1, 1);
                  if (TREE_CODE (arg11) == REAL_CST
                      && !TREE_OVERFLOW (arg11)
                      && operand_equal_p (arg0, arg10, 0))
                    {
-                     tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+                     tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
                      REAL_VALUE_TYPE c;
-                     tree arg, arglist;
+                     tree arg;
 
                      c = TREE_REAL_CST (arg11);
                      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
                      arg = build_real (type, c);
-                     arglist = build_tree_list (NULL_TREE, arg);
-                     arglist = tree_cons (NULL_TREE, arg0, arglist);
-                     return build_function_call_expr (powfn, arglist);
+                     return build_call_expr (powfn, 2, arg0, arg);
                    }
                }
 
@@ -9917,23 +10126,20 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  || fcode0 == BUILT_IN_POWF
                  || fcode0 == BUILT_IN_POWL)
                {
-                 tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-                 tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
-                                                                    1)));
+                 tree arg00 = CALL_EXPR_ARG (arg0, 0);
+                 tree arg01 = CALL_EXPR_ARG (arg0, 1);
                  if (TREE_CODE (arg01) == REAL_CST
                      && !TREE_OVERFLOW (arg01)
                      && operand_equal_p (arg1, arg00, 0))
                    {
-                     tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                     tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
                      REAL_VALUE_TYPE c;
-                     tree arg, arglist;
+                     tree arg;
 
                      c = TREE_REAL_CST (arg01);
                      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
                      arg = build_real (type, c);
-                     arglist = build_tree_list (NULL_TREE, arg);
-                     arglist = tree_cons (NULL_TREE, arg1, arglist);
-                     return build_function_call_expr (powfn, arglist);
+                     return build_call_expr (powfn, 2, arg1, arg);
                    }
                }
 
@@ -9946,9 +10152,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  if (powfn)
                    {
                      tree arg = build_real (type, dconst2);
-                     tree arglist = build_tree_list (NULL_TREE, arg);
-                     arglist = tree_cons (NULL_TREE, arg0, arglist);
-                     return build_function_call_expr (powfn, arglist);
+                     return build_call_expr (powfn, 2, arg0, arg);
                    }
                }
            }
@@ -10074,7 +10278,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       if (integer_zerop (arg1))
        return non_lvalue (fold_convert (type, arg0));
       if (integer_all_onesp (arg1))
-       return fold_build1 (BIT_NOT_EXPR, type, arg0);
+       return fold_build1 (BIT_NOT_EXPR, type, op0);
       if (operand_equal_p (arg0, arg1, 0))
        return omit_one_operand (type, integer_zero_node, arg0);
 
@@ -10480,29 +10684,27 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS)
               || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF)
               || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL))
-             && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                 TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
+             && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
+                                 CALL_EXPR_ARG (arg1, 0), 0))
            {
              tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
 
              if (tanfn != NULL_TREE)
-               return build_function_call_expr (tanfn,
-                                                TREE_OPERAND (arg0, 1));
+               return build_call_expr (tanfn, 1, CALL_EXPR_ARG (arg0, 0));
            }
 
          /* Optimize cos(x)/sin(x) as 1.0/tan(x).  */
          if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN)
               || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF)
               || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL))
-             && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                 TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
+             && operand_equal_p (CALL_EXPR_ARG (arg0, 0),
+                                 CALL_EXPR_ARG (arg1, 0), 0))
            {
              tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
 
              if (tanfn != NULL_TREE)
                {
-                 tree tmp = TREE_OPERAND (arg0, 1);
-                 tmp = build_function_call_expr (tanfn, tmp);
+                 tree tmp = build_call_expr (tanfn, 1, CALL_EXPR_ARG (arg0, 0));
                  return fold_build2 (RDIV_EXPR, type,
                                      build_real (type, dconst1), tmp);
                }
@@ -10514,8 +10716,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
               || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_TANF)
               || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_TANL)))
            {
-             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-             tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+             tree arg00 = CALL_EXPR_ARG (arg0, 0);
+             tree arg01 = CALL_EXPR_ARG (arg1, 0);
 
              if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00)))
                  && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00)))
@@ -10524,8 +10726,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  tree cosfn = mathfn_built_in (type, BUILT_IN_COS);
 
                  if (cosfn != NULL_TREE)
-                   return build_function_call_expr (cosfn,
-                                                    TREE_OPERAND (arg0, 1));
+                   return build_call_expr (cosfn, 1, arg00);
                }
            }
 
@@ -10535,8 +10736,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
               || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_SINF)
               || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_SINL)))
            {
-             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-             tree arg01 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+             tree arg00 = CALL_EXPR_ARG (arg0, 0);
+             tree arg01 = CALL_EXPR_ARG (arg1, 0);
 
              if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg00)))
                  && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg00)))
@@ -10546,8 +10747,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 
                  if (cosfn != NULL_TREE)
                    {
-                     tree tmp = TREE_OPERAND (arg0, 1);
-                     tmp = build_function_call_expr (cosfn, tmp);
+                     tree tmp = build_call_expr (cosfn, 1, arg00);
                      return fold_build2 (RDIV_EXPR, type,
                                          build_real (type, dconst1),
                                          tmp);
@@ -10560,33 +10760,47 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              || fcode0 == BUILT_IN_POWF
              || fcode0 == BUILT_IN_POWL)
            {
-             tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
-             tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
+             tree arg00 = CALL_EXPR_ARG (arg0, 0);
+             tree arg01 = CALL_EXPR_ARG (arg0, 1);
              if (TREE_CODE (arg01) == REAL_CST
                  && !TREE_OVERFLOW (arg01)
                  && operand_equal_p (arg1, arg00, 0))
                {
-                 tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                 tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
                  REAL_VALUE_TYPE c;
-                 tree arg, arglist;
+                 tree arg;
 
                  c = TREE_REAL_CST (arg01);
                  real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
                  arg = build_real (type, c);
-                 arglist = build_tree_list (NULL_TREE, arg);
-                 arglist = tree_cons (NULL_TREE, arg1, arglist);
-                 return build_function_call_expr (powfn, arglist);
+                 return build_call_expr (powfn, 2, arg1, arg);
+               }
+           }
+
+         /* Optimize a/root(b/c) into a*root(c/b).  */
+         if (BUILTIN_ROOT_P (fcode1))
+           {
+             tree rootarg = CALL_EXPR_ARG (arg1, 0);
+
+             if (TREE_CODE (rootarg) == RDIV_EXPR)
+               {
+                 tree rootfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
+                 tree b = TREE_OPERAND (rootarg, 0);
+                 tree c = TREE_OPERAND (rootarg, 1);
+
+                 tree tmp = fold_build2 (RDIV_EXPR, type, c, b);
+
+                 tmp = build_call_expr (rootfn, 1, tmp);
+                 return fold_build2 (MULT_EXPR, type, arg0, tmp);
                }
            }
 
          /* Optimize x/expN(y) into x*expN(-y).  */
          if (BUILTIN_EXPONENT_P (fcode1))
            {
-             tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
-             tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1)));
-             tree arglist = build_tree_list (NULL_TREE,
-                                             fold_convert (type, arg));
-             arg1 = build_function_call_expr (expfn, arglist);
+             tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
+             tree arg = negate_expr (CALL_EXPR_ARG (arg1, 0));
+             arg1 = build_call_expr (expfn, 1, fold_convert (type, arg));
              return fold_build2 (MULT_EXPR, type, arg0, arg1);
            }
 
@@ -10595,13 +10809,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              || fcode1 == BUILT_IN_POWF
              || fcode1 == BUILT_IN_POWL)
            {
-             tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
-             tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
-             tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
+             tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg1), 0);
+             tree arg10 = CALL_EXPR_ARG (arg1, 0);
+             tree arg11 = CALL_EXPR_ARG (arg1, 1);
              tree neg11 = fold_convert (type, negate_expr (arg11));
-             tree arglist = tree_cons (NULL_TREE, arg10,
-                                       build_tree_list (NULL_TREE, neg11));
-             arg1 = build_function_call_expr (powfn, arglist);
+             arg1 = build_call_expr (powfn, 2, arg10, neg11);
              return fold_build2 (MULT_EXPR, type, arg0, arg1);
            }
        }
@@ -10660,7 +10872,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                    "when distributing negation across "
                                    "division"),
                                   WARN_STRICT_OVERFLOW_MISC);
-         return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+         return fold_build2 (code, type,
+                             fold_convert (type, TREE_OPERAND (arg0, 0)),
                              negate_expr (arg1));
        }
       if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type))
@@ -11127,14 +11340,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
           && code == EQ_EXPR)
         return fold_build1 (TRUTH_NOT_EXPR, type, arg0);
 
-      /* If this is an equality comparison of the address of a non-weak
-        object against zero, then we know the result.  */
-      if (TREE_CODE (arg0) == ADDR_EXPR
-         && VAR_OR_FUNCTION_DECL_P (TREE_OPERAND (arg0, 0))
-         && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
-         && integer_zerop (arg1))
-       return constant_boolean_node (code != EQ_EXPR, type);
-
       /* If this is an equality comparison of the address of two non-weak,
         unaliased symbols neither of which are extern (since we do not
         have access to attributes for externs), then we know the result.  */
@@ -11199,6 +11404,24 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                         fold_convert (TREE_TYPE (arg0), arg1),
                                         TREE_OPERAND (arg0, 1)));
 
+      /* Transform comparisons of the form X +- C CMP X.  */
+      if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+         && (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+             || POINTER_TYPE_P (TREE_TYPE (arg0))))
+       {
+         tree cst = TREE_OPERAND (arg0, 1);
+
+         if (code == EQ_EXPR
+             && !integer_zerop (cst))
+           return omit_two_operands (type, boolean_false_node,
+                                     TREE_OPERAND (arg0, 0), arg1);
+         else
+           return omit_two_operands (type, boolean_true_node,
+                                     TREE_OPERAND (arg0, 0), arg1);
+       }
+
       /* If we have X - Y == 0, we can convert that to X == Y and similarly
         for !=.  Don't do this for ordered comparisons due to overflow.  */
       if (TREE_CODE (arg0) == MINUS_EXPR
@@ -11254,7 +11477,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              || TREE_CODE (arg0) == ROUND_MOD_EXPR)
          && integer_pow2p (TREE_OPERAND (arg0, 1)))
        {
-         tree newtype = lang_hooks.types.unsigned_type (TREE_TYPE (arg0));
+         tree newtype = unsigned_type_for (TREE_TYPE (arg0));
          tree newmod = fold_build2 (TREE_CODE (arg0), newtype,
                                     fold_convert (newtype,
                                                   TREE_OPERAND (arg0, 0)),
@@ -11386,16 +11609,14 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && integer_zerop (arg1))
        {
          tree fndecl = get_callee_fndecl (arg0);
-         tree arglist;
 
          if (fndecl
              && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
              && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
-             && (arglist = TREE_OPERAND (arg0, 1))
-             && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
-             && ! TREE_CHAIN (arglist))
+             && call_expr_nargs (arg0) == 1
+             && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (arg0, 0))) == POINTER_TYPE)
            {
-             tree iref = build_fold_indirect_ref (TREE_VALUE (arglist));
+             tree iref = build_fold_indirect_ref (CALL_EXPR_ARG (arg0, 0));
              return fold_build2 (code, type, iref,
                                  build_int_cst (TREE_TYPE (iref), 0));
            }
@@ -11416,7 +11637,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            {
              if (TYPE_UNSIGNED (itype))
                {
-                 itype = lang_hooks.types.signed_type (itype);
+                 itype = signed_type_for (itype);
                  arg00 = fold_convert (itype, arg00);
                }
              return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
@@ -11581,6 +11802,79 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                                          arg01, arg11)),
                                arg10);
        }
+
+      /* Attempt to simplify equality/inequality comparisons of complex
+        values.  Only lower the comparison if the result is known or
+        can be simplified to a single scalar comparison.  */
+      if ((TREE_CODE (arg0) == COMPLEX_EXPR
+          || TREE_CODE (arg0) == COMPLEX_CST)
+         && (TREE_CODE (arg1) == COMPLEX_EXPR
+             || TREE_CODE (arg1) == COMPLEX_CST))
+       {
+         tree real0, imag0, real1, imag1;
+         tree rcond, icond;
+
+         if (TREE_CODE (arg0) == COMPLEX_EXPR)
+           {
+             real0 = TREE_OPERAND (arg0, 0);
+             imag0 = TREE_OPERAND (arg0, 1);
+           }
+         else
+           {
+             real0 = TREE_REALPART (arg0);
+             imag0 = TREE_IMAGPART (arg0);
+           }
+
+         if (TREE_CODE (arg1) == COMPLEX_EXPR)
+           {
+             real1 = TREE_OPERAND (arg1, 0);
+             imag1 = TREE_OPERAND (arg1, 1);
+           }
+         else
+           {
+             real1 = TREE_REALPART (arg1);
+             imag1 = TREE_IMAGPART (arg1);
+           }
+
+         rcond = fold_binary (code, type, real0, real1);
+         if (rcond && TREE_CODE (rcond) == INTEGER_CST)
+           {
+             if (integer_zerop (rcond))
+               {
+                 if (code == EQ_EXPR)
+                   return omit_two_operands (type, boolean_false_node,
+                                             imag0, imag1);
+                 return fold_build2 (NE_EXPR, type, imag0, imag1);
+               }
+             else
+               {
+                 if (code == NE_EXPR)
+                   return omit_two_operands (type, boolean_true_node,
+                                             imag0, imag1);
+                 return fold_build2 (EQ_EXPR, type, imag0, imag1);
+               }
+           }
+
+         icond = fold_binary (code, type, imag0, imag1);
+         if (icond && TREE_CODE (icond) == INTEGER_CST)
+           {
+             if (integer_zerop (icond))
+               {
+                 if (code == EQ_EXPR)
+                   return omit_two_operands (type, boolean_false_node,
+                                             real0, real1);
+                 return fold_build2 (NE_EXPR, type, real0, real1);
+               }
+             else
+               {
+                 if (code == NE_EXPR)
+                   return omit_two_operands (type, boolean_true_node,
+                                             real0, real1);
+                 return fold_build2 (EQ_EXPR, type, real0, real1);
+               }
+           }
+       }
+
       return NULL_TREE;
 
     case LT_EXPR:
@@ -11713,7 +12007,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
                    fold_overflow_warning (("assuming signed overflow does "
                                            "not occur when assuming that "
-                                           "(X - c) >= X is always true"),
+                                           "(X - c) >= X is always false"),
                                           WARN_STRICT_OVERFLOW_ALL);
                  return constant_boolean_node (0, type);
                }
@@ -11807,13 +12101,13 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  return omit_one_operand (type, integer_zero_node, arg0);
 
                case GE_EXPR:
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+                 return fold_build2 (EQ_EXPR, type, op0, op1);
 
                case LE_EXPR:
                  return omit_one_operand (type, integer_one_node, arg0);
 
                case LT_EXPR:
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+                 return fold_build2 (NE_EXPR, type, op0, op1);
 
                /* The GE_EXPR and LT_EXPR cases above are not normally
                   reached because of previous transformations.  */
@@ -11829,11 +12123,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                case GT_EXPR:
                  arg1 = const_binop (PLUS_EXPR, arg1,
                                      build_int_cst (TREE_TYPE (arg1), 1), 0);
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+                 return fold_build2 (EQ_EXPR, type,
+                                     fold_convert (TREE_TYPE (arg1), arg0),
+                                     arg1);
                case LE_EXPR:
                  arg1 = const_binop (PLUS_EXPR, arg1,
                                      build_int_cst (TREE_TYPE (arg1), 1), 0);
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+                 return fold_build2 (NE_EXPR, type,
+                                     fold_convert (TREE_TYPE (arg1), arg0),
+                                     arg1);
                default:
                  break;
                }
@@ -11846,7 +12144,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  return omit_one_operand (type, integer_zero_node, arg0);
 
                case LE_EXPR:
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+                 return fold_build2 (EQ_EXPR, type, op0, op1);
 
                case GE_EXPR:
                  return omit_one_operand (type, integer_one_node, arg0);
@@ -11864,10 +12162,14 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                {
                case GE_EXPR:
                  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold_build2 (NE_EXPR, type, arg0, arg1);
+                 return fold_build2 (NE_EXPR, type,
+                                     fold_convert (TREE_TYPE (arg1), arg0),
+                                     arg1);
                case LT_EXPR:
                  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
+                 return fold_build2 (EQ_EXPR, type,
+                                     fold_convert (TREE_TYPE (arg1), arg0),
+                                     arg1);
                default:
                  break;
                }
@@ -11887,12 +12189,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                   and X >= signed_max+1 because previous transformations.  */
                if (code == LE_EXPR || code == GT_EXPR)
                  {
-                   tree st0, st1;
-                   st0 = lang_hooks.types.signed_type (TREE_TYPE (arg0));
-                   st1 = lang_hooks.types.signed_type (TREE_TYPE (arg1));
-                   return fold_build2 (code == LE_EXPR ? GE_EXPR: LT_EXPR,
-                                       type, fold_convert (st0, arg0),
-                                       build_int_cst (st1, 0));
+                   tree st;
+                   st = signed_type_for (TREE_TYPE (arg1));
+                   return fold_build2 (code == LE_EXPR ? GE_EXPR : LT_EXPR,
+                                       type, fold_convert (st, arg0),
+                                       build_int_cst (st, 0));
                  }
              }
          }
@@ -12279,13 +12580,13 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
              if ((TREE_INT_CST_HIGH (arg1) & mask_hi) == mask_hi
                  && (TREE_INT_CST_LOW (arg1) & mask_lo) == mask_lo)
                {
-                 tem_type = lang_hooks.types.signed_type (TREE_TYPE (tem));
+                 tem_type = signed_type_for (TREE_TYPE (tem));
                  tem = fold_convert (tem_type, tem);
                }
              else if ((TREE_INT_CST_HIGH (arg1) & mask_hi) == 0
                       && (TREE_INT_CST_LOW (arg1) & mask_lo) == 0)
                {
-                 tem_type = lang_hooks.types.unsigned_type (TREE_TYPE (tem));
+                 tem_type = unsigned_type_for (TREE_TYPE (tem));
                  tem = fold_convert (tem_type, tem);
                }
              else
@@ -12376,15 +12677,13 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
       return NULL_TREE;
 
     case CALL_EXPR:
-      /* Check for a built-in function.  */
-      if (TREE_CODE (op0) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (op0, 0)) == FUNCTION_DECL
-         && DECL_BUILT_IN (TREE_OPERAND (op0, 0)))
-       return fold_builtin (TREE_OPERAND (op0, 0), op1, false);
-      return NULL_TREE;
+      /* CALL_EXPRs used to be ternary exprs.  Catch any mistaken uses
+        of fold_ternary on them.  */
+      gcc_unreachable ();
 
     case BIT_FIELD_REF:
-      if (TREE_CODE (arg0) == VECTOR_CST
+      if ((TREE_CODE (arg0) == VECTOR_CST
+          || (TREE_CODE (arg0) == CONSTRUCTOR && TREE_CONSTANT (arg0)))
          && type == TREE_TYPE (TREE_TYPE (arg0))
          && host_integerp (arg1, 1)
          && host_integerp (op2, 1))
@@ -12398,7 +12697,18 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
              && (idx = idx / width)
                 < TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))
            {
-             tree elements = TREE_VECTOR_CST_ELTS (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);
+               }
              while (idx-- > 0 && elements)
                elements = TREE_CHAIN (elements);
              if (elements)
@@ -12439,6 +12749,18 @@ fold (tree expr)
   if (kind == tcc_constant)
     return t;
 
+  /* CALL_EXPR-like objects with variable numbers of operands are
+     treated specially.  */
+  if (kind == tcc_vl_exp)
+    {
+      if (code == CALL_EXPR)
+       {
+         tem = fold_call_expr (expr, false);
+         return tem ? tem : expr;
+       }
+      return expr;
+    }
+
   if (IS_EXPR_CODE_CLASS (kind)
       || IS_GIMPLE_STMT_CODE_CLASS (kind))
     {
@@ -12587,7 +12909,8 @@ recursive_label:
   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 != TREE_LIST
+      && code != SSA_NAME)
     fold_checksum_tree (TREE_CHAIN (expr), ctx, ht);
   switch (TREE_CODE_CLASS (code))
     {
@@ -12632,7 +12955,8 @@ recursive_label:
     case tcc_unary:
     case tcc_binary:
     case tcc_statement:
-      len = TREE_CODE_LENGTH (code);
+    case tcc_vl_exp:
+      len = TREE_OPERAND_LENGTH (expr);
       for (i = 0; i < len; ++i)
        fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht);
       break;
@@ -12682,6 +13006,30 @@ recursive_label:
     }
 }
 
+/* Helper function for outputting the checksum of a tree T.  When
+   debugging with gdb, you can "define mynext" to be "next" followed
+   by "call debug_fold_checksum (op0)", then just trace down till the
+   outputs differ.  */
+
+void
+debug_fold_checksum (tree t)
+{
+  int i;
+  unsigned char checksum[16];
+  struct md5_ctx ctx;
+  htab_t ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
+  
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (t, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum);
+  htab_empty (ht);
+
+  for (i = 0; i < 16; i++)
+    fprintf (stderr, "%d ", checksum[i]);
+
+  fprintf (stderr, "\n");
+}
+
 #endif
 
 /* Fold a unary tree expression with code CODE of type TYPE with an
@@ -12811,7 +13159,8 @@ fold_build3_stat (enum tree_code code, tree type, tree op0, tree op1, tree op2
   md5_finish_ctx (&ctx, checksum_before_op2);
   htab_empty (ht);
 #endif
-  
+
+  gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
   tem = fold_ternary (code, type, op0, op1, op2);
   if (!tem)
     tem =  build3_stat (code, type, op0, op1, op2 PASS_MEM_STAT);
@@ -12844,6 +13193,60 @@ fold_build3_stat (enum tree_code code, tree type, tree op0, tree op1, tree op2
   return tem;
 }
 
+/* Fold a CALL_EXPR expression of type TYPE with operands FN and NARGS
+   arguments in ARGARRAY, and a null static chain.
+   Return a folded expression if successful.  Otherwise, return a CALL_EXPR
+   of type TYPE from the given operands as constructed by build_call_array.  */
+
+tree
+fold_build_call_array (tree type, tree fn, int nargs, tree *argarray)
+{
+  tree tem;
+#ifdef ENABLE_FOLD_CHECKING
+  unsigned char checksum_before_fn[16],
+                checksum_before_arglist[16],
+               checksum_after_fn[16],
+               checksum_after_arglist[16];
+  struct md5_ctx ctx;
+  htab_t ht;
+  int i;
+
+  ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (fn, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before_fn);
+  htab_empty (ht);
+
+  md5_init_ctx (&ctx);
+  for (i = 0; i < nargs; i++)
+    fold_checksum_tree (argarray[i], &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_before_arglist);
+  htab_empty (ht);
+#endif
+
+  tem = fold_builtin_call_array (type, fn, nargs, argarray);
+      
+#ifdef ENABLE_FOLD_CHECKING
+  md5_init_ctx (&ctx);
+  fold_checksum_tree (fn, &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after_fn);
+  htab_empty (ht);
+
+  if (memcmp (checksum_before_fn, checksum_after_fn, 16))
+    fold_check_failed (fn, tem);
+  
+  md5_init_ctx (&ctx);
+  for (i = 0; i < nargs; i++)
+    fold_checksum_tree (argarray[i], &ctx, ht);
+  md5_finish_ctx (&ctx, checksum_after_arglist);
+  htab_delete (ht);
+
+  if (memcmp (checksum_before_arglist, checksum_after_arglist, 16))
+    fold_check_failed (NULL_TREE, tem);
+#endif
+  return tem;
+}
+
 /* Perform constant folding and related simplification of initializer
    expression EXPR.  These behave identically to "fold_buildN" but ignore
    potential run-time traps and exceptions that fold must preserve.  */
@@ -12904,6 +13307,19 @@ fold_build3_initializer (enum tree_code code, tree type, tree op0, tree op1,
   return result;
 }
 
+tree
+fold_build_call_array_initializer (tree type, tree fn,
+                                  int nargs, tree *argarray)
+{
+  tree result;
+  START_FOLD_INIT;
+
+  result = fold_build_call_array (type, fn, nargs, argarray);
+
+  END_FOLD_INIT;
+  return result;
+}
+
 #undef START_FOLD_INIT
 #undef END_FOLD_INIT
 
@@ -12947,7 +13363,7 @@ fold_build3_initializer (enum tree_code code, tree type, tree op0, tree op1,
    (where the same SAVE_EXPR (J) is used in the original and the
    transformed version).  */
 
-static int
+int
 multiple_of_p (tree type, tree top, tree bottom)
 {
   if (operand_equal_p (top, bottom, 0))
@@ -13008,6 +13424,7 @@ multiple_of_p (tree type, tree top, tree bottom)
 
     case INTEGER_CST:
       if (TREE_CODE (bottom) != INTEGER_CST
+         || integer_zerop (bottom)
          || (TYPE_UNSIGNED (type)
              && (tree_int_cst_sgn (top) < 0
                  || tree_int_cst_sgn (bottom) < 0)))
@@ -13059,6 +13476,7 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
     case REAL_CST:
       return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t));
 
+    case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
       if (FLOAT_TYPE_P (TREE_TYPE (t)))
        return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
@@ -13138,6 +13556,7 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
     case SAVE_EXPR:
     case NON_LVALUE_EXPR:
     case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
       return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
                                            strict_overflow_p);
 
@@ -13223,7 +13642,6 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
     case CALL_EXPR:
       {
        tree fndecl = get_callee_fndecl (t);
-       tree arglist = TREE_OPERAND (t, 1);
        if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
          switch (DECL_FUNCTION_CODE (fndecl))
            {
@@ -13251,7 +13669,7 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
              /* sqrt(-0.0) is -0.0.  */
              if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
                return true;
-             return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
                                                    strict_overflow_p);
 
            CASE_FLT_FN (BUILT_IN_ASINH):
@@ -13277,57 +13695,58 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
            CASE_FLT_FN (BUILT_IN_NEARBYINT):
            CASE_FLT_FN (BUILT_IN_RINT):
            CASE_FLT_FN (BUILT_IN_ROUND):
+           CASE_FLT_FN (BUILT_IN_SCALB):
+           CASE_FLT_FN (BUILT_IN_SCALBLN):
+           CASE_FLT_FN (BUILT_IN_SCALBN):
            CASE_FLT_FN (BUILT_IN_SIGNBIT):
+           CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
            CASE_FLT_FN (BUILT_IN_SINH):
            CASE_FLT_FN (BUILT_IN_TANH):
            CASE_FLT_FN (BUILT_IN_TRUNC):
              /* True if the 1st argument is nonnegative.  */
-             return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
                                                    strict_overflow_p);
 
            CASE_FLT_FN (BUILT_IN_FMAX):
              /* True if the 1st OR 2nd arguments are nonnegative.  */
-             return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+             return (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
                                                     strict_overflow_p)
-                     || (tree_expr_nonnegative_warnv_p
-                         (TREE_VALUE (TREE_CHAIN (arglist)),
-                          strict_overflow_p)));
+                     || (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
+                                                        strict_overflow_p)));
 
            CASE_FLT_FN (BUILT_IN_FMIN):
              /* True if the 1st AND 2nd arguments are nonnegative.  */
-             return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+             return (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
                                                     strict_overflow_p)
-                     && (tree_expr_nonnegative_warnv_p
-                         (TREE_VALUE (TREE_CHAIN (arglist)),
-                          strict_overflow_p)));
+                     && (tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
+                                                        strict_overflow_p)));
 
            CASE_FLT_FN (BUILT_IN_COPYSIGN):
              /* True if the 2nd argument is nonnegative.  */
-             return (tree_expr_nonnegative_warnv_p
-                     (TREE_VALUE (TREE_CHAIN (arglist)),
-                      strict_overflow_p));
+             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 1),
+                                                   strict_overflow_p);
 
            CASE_FLT_FN (BUILT_IN_POWI):
              /* True if the 1st argument is nonnegative or the second
                 argument is an even integer.  */
-             if (TREE_CODE (TREE_VALUE (TREE_CHAIN (arglist))) == INTEGER_CST)
+             if (TREE_CODE (CALL_EXPR_ARG (t, 1)) == INTEGER_CST)
                {
-                 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+                 tree arg1 = CALL_EXPR_ARG (t, 1);
                  if ((TREE_INT_CST_LOW (arg1) & 1) == 0)
                    return true;
                }
-             return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
                                                    strict_overflow_p);
 
            CASE_FLT_FN (BUILT_IN_POW):
              /* True if the 1st argument is nonnegative or the second
                 argument is an even integer valued real.  */
-             if (TREE_CODE (TREE_VALUE (TREE_CHAIN (arglist))) == REAL_CST)
+             if (TREE_CODE (CALL_EXPR_ARG (t, 1)) == REAL_CST)
                {
                  REAL_VALUE_TYPE c;
                  HOST_WIDE_INT n;
 
-                 c = TREE_REAL_CST (TREE_VALUE (TREE_CHAIN (arglist)));
+                 c = TREE_REAL_CST (CALL_EXPR_ARG (t, 1));
                  n = real_to_integer (&c);
                  if ((n & 1) == 0)
                    {
@@ -13338,7 +13757,7 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
                        return true;
                    }
                }
-             return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+             return tree_expr_nonnegative_warnv_p (CALL_EXPR_ARG (t, 0),
                                                    strict_overflow_p);
 
            default:
@@ -13349,9 +13768,14 @@ tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
       /* ... fall through ...  */
 
     default:
-      if (truth_value_p (TREE_CODE (t)))
-       /* Truth values evaluate to 0 or 1, which is nonnegative.  */
-       return true;
+      {
+       tree type = TREE_TYPE (t);
+       if ((TYPE_PRECISION (type) != 1 || TYPE_UNSIGNED (type))
+           && truth_value_p (TREE_CODE (t)))
+         /* Truth values evaluate to 0 or 1, which is nonnegative unless we
+             have a signed:1 type (where the value is -1 and 0).  */
+         return true;
+      }
     }
 
   /* We don't know sign of `t', so be conservative and return false.  */
@@ -13408,6 +13832,7 @@ tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p)
     case INTEGER_CST:
       return !integer_zerop (t);
 
+    case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
       if (TYPE_OVERFLOW_UNDEFINED (type))
        {
@@ -13645,10 +14070,9 @@ fold_read_from_constant_string (tree exp)
          && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (string))))
              == MODE_INT)
          && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) == 1))
-       return fold_convert (TREE_TYPE (exp),
-                            build_int_cst (NULL_TREE,
-                                           (TREE_STRING_POINTER (string)
-                                            [TREE_INT_CST_LOW (index)])));
+       return build_int_cst_type (TREE_TYPE (exp),
+                                  (TREE_STRING_POINTER (string)
+                                   [TREE_INT_CST_LOW (index)]));
     }
   return NULL;
 }
@@ -13812,6 +14236,23 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
       return constant_boolean_node (real_compare (code, c0, c1), type);
     }
 
+  /* Handle equality/inequality of complex constants.  */
+  if (TREE_CODE (op0) == COMPLEX_CST && TREE_CODE (op1) == COMPLEX_CST)
+    {
+      tree rcond = fold_relational_const (code, type,
+                                         TREE_REALPART (op0),
+                                         TREE_REALPART (op1));
+      tree icond = fold_relational_const (code, type,
+                                         TREE_IMAGPART (op0),
+                                         TREE_IMAGPART (op1));
+      if (code == EQ_EXPR)
+       return fold_build2 (TRUTH_ANDIF_EXPR, type, rcond, icond);
+      else if (code == NE_EXPR)
+       return fold_build2 (TRUTH_ORIF_EXPR, type, rcond, icond);
+      else
+       return NULL_TREE;
+    }
+
   /* From here on we only handle LT, LE, GT, GE, EQ and NE.
 
      To compute GT, swap the arguments and do LT.
@@ -13858,9 +14299,9 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
   return constant_boolean_node (result, type);
 }
 
-/* Build an expression for the a clean point containing EXPR with type TYPE.
-   Don't build a cleanup point expression for EXPR which don't have side
-   effects.  */
+/* If necessary, return a CLEANUP_POINT_EXPR for EXPR with the
+   indicated TYPE.  If no CLEANUP_POINT_EXPR is necessary, return EXPR
+   itself.  */
 
 tree
 fold_build_cleanup_point_expr (tree type, tree expr)
@@ -13888,45 +14329,6 @@ fold_build_cleanup_point_expr (tree type, tree expr)
   return build1 (CLEANUP_POINT_EXPR, type, expr);
 }
 
-/* Build an expression for the address of T.  Folds away INDIRECT_REF to
-   avoid confusing the gimplify process.  */
-
-tree
-build_fold_addr_expr_with_type (tree t, tree ptrtype)
-{
-  /* The size of the object is not relevant when talking about its address.  */
-  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)
-    {
-      t = TREE_OPERAND (t, 0);
-      if (TREE_TYPE (t) != ptrtype)
-       t = build1 (NOP_EXPR, ptrtype, t);
-    }
-  else
-    {
-      tree base = t;
-
-      while (handled_component_p (base))
-       base = TREE_OPERAND (base, 0);
-      if (DECL_P (base))
-       TREE_ADDRESSABLE (base) = 1;
-
-      t = build1 (ADDR_EXPR, ptrtype, t);
-    }
-
-  return t;
-}
-
-tree
-build_fold_addr_expr (tree t)
-{
-  return build_fold_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
-}
-
 /* Given a pointer value OP0 and a type TYPE, return a simplified version
    of an indirection through OP0, or NULL_TREE if no simplification is
    possible.  */
@@ -13983,7 +14385,7 @@ fold_indirect_ref_1 (tree type, tree op0)
     }
 
   /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
-  if (TREE_CODE (sub) == PLUS_EXPR
+  if (TREE_CODE (sub) == POINTER_PLUS_EXPR
       && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
     {
       tree op00 = TREE_OPERAND (sub, 0);
@@ -14230,7 +14632,7 @@ split_address_to_core_and_offset (tree exp,
       core = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, pbitpos,
                                  poffset, &mode, &unsignedp, &volatilep,
                                  false);
-      core = build_fold_addr_expr (core);
+      core = fold_addr_expr (core);
     }
   else
     {
@@ -14336,19 +14738,17 @@ fold_strip_sign_ops (tree exp)
        {
        CASE_FLT_FN (BUILT_IN_COPYSIGN):
          /* Strip copysign function call, return the 1st argument. */
-         arg0 = TREE_VALUE (TREE_OPERAND (exp, 1));
-         arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (exp, 1)));
+         arg0 = CALL_EXPR_ARG (exp, 0);
+         arg1 = CALL_EXPR_ARG (exp, 1);
          return omit_one_operand (TREE_TYPE (exp), arg0, arg1);
 
        default:
          /* Strip sign ops from the argument of "odd" math functions.  */
          if (negate_mathfn_p (fcode))
             {
-             arg0 = fold_strip_sign_ops (TREE_VALUE (TREE_OPERAND (exp, 1)));
+             arg0 = fold_strip_sign_ops (CALL_EXPR_ARG (exp, 0));
              if (arg0)
-               return build_function_call_expr (get_callee_fndecl (exp),
-                                                build_tree_list (NULL_TREE,
-                                                                 arg0));
+               return build_call_expr (get_callee_fndecl (exp), 1, arg0);
            }
          break;
        }