OSDN Git Service

2004-05-21 Frank Ch. Eigler <fche@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 71f1e9b..2c89c5b 100644 (file)
@@ -65,12 +65,10 @@ static bool negate_expr_p (tree);
 static tree negate_expr (tree);
 static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
 static tree associate_trees (tree, tree, enum tree_code, tree);
-static tree int_const_binop (enum tree_code, tree, tree, int);
 static tree const_binop (enum tree_code, tree, tree, int);
 static hashval_t size_htab_hash (const void *);
 static int size_htab_eq (const void *, const void *);
 static tree fold_convert_const (enum tree_code, tree, tree);
-static tree fold_convert (tree, tree);
 static enum tree_code invert_tree_comparison (enum tree_code);
 static enum tree_code swap_tree_comparison (enum tree_code);
 static int comparison_to_compcode (enum tree_code);
@@ -100,19 +98,23 @@ static tree fold_truthop (enum tree_code, tree, tree, tree);
 static tree optimize_minmax_comparison (tree);
 static tree extract_muldiv (tree, tree, enum tree_code, tree);
 static tree extract_muldiv_1 (tree, tree, enum tree_code, tree);
-static tree strip_compound_expr (tree, tree);
 static int multiple_of_p (tree, tree, tree);
 static tree constant_boolean_node (int, tree);
-static int count_cond (tree, int);
 static tree fold_binary_op_with_conditional_arg (enum tree_code, tree, tree,
                                                 tree, int);
 static bool fold_real_zero_addition_p (tree, tree, int);
 static tree fold_mathfn_compare (enum built_in_function, enum tree_code,
                                 tree, tree, tree);
 static tree fold_inf_compare (enum tree_code, tree, tree, tree);
+static tree fold_div_compare (enum tree_code, tree, tree, tree);
 static bool reorder_operands_p (tree, tree);
 static bool tree_swap_operands_p (tree, tree, bool);
 
+static tree fold_negate_const (tree, tree);
+static tree fold_abs_const (tree, tree);
+static tree fold_relational_const (enum tree_code, tree, tree, tree);
+static tree fold_relational_hi_lo (enum tree_code *, const tree, tree *, tree *);
+
 /* The following constants represent a bit based encoding of GCC's
    comparison operators.  This encoding simplifies transformations
    on relational comparison operators, such as AND and OR.  */
@@ -220,7 +222,7 @@ force_fit_type (tree t, int overflow)
 
   /* Unsigned types do not suffer sign extension or overflow unless they
      are a sizetype.  */
-  if (TREE_UNSIGNED (TREE_TYPE (t))
+  if (TYPE_UNSIGNED (TREE_TYPE (t))
       && ! (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
            && TYPE_IS_SIZETYPE (TREE_TYPE (t))))
     return overflow;
@@ -374,10 +376,8 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
       return;
     }
 
-#ifdef SHIFT_COUNT_TRUNCATED
   if (SHIFT_COUNT_TRUNCATED)
     count %= prec;
-#endif
 
   if (count >= 2 * HOST_BITS_PER_WIDE_INT)
     {
@@ -437,10 +437,8 @@ rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
              ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
              : 0);
 
-#ifdef SHIFT_COUNT_TRUNCATED
   if (SHIFT_COUNT_TRUNCATED)
     count %= prec;
-#endif
 
   if (count >= 2 * HOST_BITS_PER_WIDE_INT)
     {
@@ -722,7 +720,7 @@ div_and_round_double (enum tree_code code, int uns,
   if (quo_neg)
     neg_double (*lquo, *hquo, lquo, hquo);
 
-  /* compute trial remainder:  rem = num - (quo * den)  */
+  /* Compute trial remainder:  rem = num - (quo * den)  */
   mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem);
   neg_double (*lrem, *hrem, lrem, hrem);
   add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
@@ -853,7 +851,7 @@ negate_expr_p (tree t)
   switch (TREE_CODE (t))
     {
     case INTEGER_CST:
-      if (TREE_UNSIGNED (type) || ! flag_trapv)
+      if (TYPE_UNSIGNED (type) || ! flag_trapv)
        return true;
 
       /* Check that -CST will not overflow type.  */
@@ -897,7 +895,7 @@ negate_expr_p (tree t)
                                    TREE_OPERAND (t, 1));
 
     case MULT_EXPR:
-      if (TREE_UNSIGNED (TREE_TYPE (t)))
+      if (TYPE_UNSIGNED (TREE_TYPE (t)))
         break;
 
       /* Fall through.  */
@@ -924,6 +922,18 @@ negate_expr_p (tree t)
        return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1)));
       break;
 
+    case RSHIFT_EXPR:
+      /* Optimize -((int)x >> 31) into (unsigned)x >> 31.  */
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
+       {
+         tree op1 = TREE_OPERAND (t, 1);
+         if (TREE_INT_CST_HIGH (op1) == 0
+             && (unsigned HOST_WIDE_INT) (TYPE_PRECISION (type) - 1)
+                == TREE_INT_CST_LOW (op1))
+           return true;
+       }
+      break;
+
     default:
       break;
     }
@@ -948,28 +958,15 @@ negate_expr (tree t)
   switch (TREE_CODE (t))
     {
     case INTEGER_CST:
-      {
-       unsigned HOST_WIDE_INT low;
-       HOST_WIDE_INT high;
-       int overflow = neg_double (TREE_INT_CST_LOW (t),
-                                  TREE_INT_CST_HIGH (t),
-                                  &low, &high);
-       tem = build_int_2 (low, high);
-       TREE_TYPE (tem) = type;
-       TREE_OVERFLOW (tem)
-         = (TREE_OVERFLOW (t)
-            | force_fit_type (tem, overflow && !TREE_UNSIGNED (type)));
-       TREE_CONSTANT_OVERFLOW (tem)
-         = TREE_OVERFLOW (tem) | TREE_CONSTANT_OVERFLOW (t);
-      }
+      tem = fold_negate_const (t, type);
       if (! TREE_OVERFLOW (tem)
-         || TREE_UNSIGNED (type)
+         || TYPE_UNSIGNED (type)
          || ! flag_trapv)
        return tem;
       break;
 
     case REAL_CST:
-      tem = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (t)));
+      tem = fold_negate_const (t, type);
       /* Two's complement FP formats, such as c4x, may overflow.  */
       if (! TREE_OVERFLOW (tem) || ! flag_trapping_math)
        return fold_convert (type, tem);
@@ -998,16 +995,21 @@ negate_expr (tree t)
          if (negate_expr_p (TREE_OPERAND (t, 1))
              && reorder_operands_p (TREE_OPERAND (t, 0),
                                     TREE_OPERAND (t, 1)))
-           return fold_convert (type,
-                                fold (build (MINUS_EXPR, TREE_TYPE (t),
-                                             negate_expr (TREE_OPERAND (t, 1)),
-                                             TREE_OPERAND (t, 0))));
+           {
+             tem = negate_expr (TREE_OPERAND (t, 1));
+             tem = fold (build2 (MINUS_EXPR, TREE_TYPE (t),
+                                 tem, TREE_OPERAND (t, 0)));
+             return fold_convert (type, tem);
+           }
+
          /* -(A + B) -> (-A) - B.  */
          if (negate_expr_p (TREE_OPERAND (t, 0)))
-           return fold_convert (type,
-                                fold (build (MINUS_EXPR, TREE_TYPE (t),
-                                             negate_expr (TREE_OPERAND (t, 0)),
-                                             TREE_OPERAND (t, 1))));
+           {
+             tem = negate_expr (TREE_OPERAND (t, 0));
+             tem = fold (build2 (MINUS_EXPR, TREE_TYPE (t),
+                                 tem, TREE_OPERAND (t, 1)));
+             return fold_convert (type, tem);
+           }
        }
       break;
 
@@ -1016,13 +1018,13 @@ negate_expr (tree t)
       if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
          && reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)))
        return fold_convert (type,
-                            fold (build (MINUS_EXPR, TREE_TYPE (t),
-                                         TREE_OPERAND (t, 1),
-                                         TREE_OPERAND (t, 0))));
+                            fold (build2 (MINUS_EXPR, TREE_TYPE (t),
+                                          TREE_OPERAND (t, 1),
+                                          TREE_OPERAND (t, 0))));
       break;
 
     case MULT_EXPR:
-      if (TREE_UNSIGNED (TREE_TYPE (t)))
+      if (TYPE_UNSIGNED (TREE_TYPE (t)))
         break;
 
       /* Fall through.  */
@@ -1033,15 +1035,15 @@ negate_expr (tree t)
          tem = TREE_OPERAND (t, 1);
          if (negate_expr_p (tem))
            return fold_convert (type,
-                                fold (build (TREE_CODE (t), TREE_TYPE (t),
-                                             TREE_OPERAND (t, 0),
-                                             negate_expr (tem))));
+                                fold (build2 (TREE_CODE (t), TREE_TYPE (t),
+                                              TREE_OPERAND (t, 0),
+                                              negate_expr (tem))));
          tem = TREE_OPERAND (t, 0);
          if (negate_expr_p (tem))
            return fold_convert (type,
-                                fold (build (TREE_CODE (t), TREE_TYPE (t),
-                                             negate_expr (tem),
-                                             TREE_OPERAND (t, 1))));
+                                fold (build2 (TREE_CODE (t), TREE_TYPE (t),
+                                              negate_expr (tem),
+                                              TREE_OPERAND (t, 1))));
        }
       break;
 
@@ -1069,6 +1071,25 @@ negate_expr (tree t)
        }
       break;
 
+    case RSHIFT_EXPR:
+      /* Optimize -((int)x >> 31) into (unsigned)x >> 31.  */
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
+       {
+         tree op1 = TREE_OPERAND (t, 1);
+         if (TREE_INT_CST_HIGH (op1) == 0
+             && (unsigned HOST_WIDE_INT) (TYPE_PRECISION (type) - 1)
+                == TREE_INT_CST_LOW (op1))
+           {
+             tree ntype = TYPE_UNSIGNED (type)
+                          ? lang_hooks.types.signed_type (type)
+                          : lang_hooks.types.unsigned_type (type);
+             tree temp = fold_convert (ntype, TREE_OPERAND (t, 0));
+             temp = fold (build2 (RSHIFT_EXPR, ntype, temp, op1));
+             return fold_convert (type, temp);
+           }
+       }
+      break;
+
     default:
       break;
     }
@@ -1193,18 +1214,18 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type)
       if (code == PLUS_EXPR)
        {
          if (TREE_CODE (t1) == NEGATE_EXPR)
-           return build (MINUS_EXPR, type, fold_convert (type, t2),
-                         fold_convert (type, TREE_OPERAND (t1, 0)));
+           return build2 (MINUS_EXPR, type, fold_convert (type, t2),
+                          fold_convert (type, TREE_OPERAND (t1, 0)));
          else if (TREE_CODE (t2) == NEGATE_EXPR)
-           return build (MINUS_EXPR, type, fold_convert (type, t1),
-                         fold_convert (type, TREE_OPERAND (t2, 0)));
+           return build2 (MINUS_EXPR, type, fold_convert (type, t1),
+                          fold_convert (type, TREE_OPERAND (t2, 0)));
        }
-      return build (code, type, fold_convert (type, t1),
-                   fold_convert (type, t2));
+      return build2 (code, type, fold_convert (type, t1),
+                    fold_convert (type, t2));
     }
 
-  return fold (build (code, type, fold_convert (type, t1),
-                     fold_convert (type, t2)));
+  return fold (build2 (code, type, fold_convert (type, t1),
+                      fold_convert (type, t2)));
 }
 \f
 /* Combine two integer constants ARG1 and ARG2 under operation CODE
@@ -1212,7 +1233,7 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type)
 
    If NOTRUNC is nonzero, do not truncate the result to fit the data type.  */
 
-static tree
+tree
 int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
 {
   unsigned HOST_WIDE_INT int1l, int2l;
@@ -1223,7 +1244,7 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
   HOST_WIDE_INT garbageh;
   tree t;
   tree type = TREE_TYPE (arg1);
-  int uns = TREE_UNSIGNED (type);
+  int uns = TYPE_UNSIGNED (type);
   int is_sizetype
     = (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type));
   int overflow = 0;
@@ -1646,7 +1667,7 @@ size_binop (enum tree_code code, tree arg0, tree arg1)
   if (arg0 == error_mark_node || arg1 == error_mark_node)
     return error_mark_node;
 
-  return fold (build (code, type, arg0, arg1));
+  return fold (build2 (code, type, arg0, arg1));
 }
 
 /* Given two values, either both of sizetype or both of bitsizetype,
@@ -1664,7 +1685,7 @@ size_diffop (tree arg0, tree arg1)
     abort ();
 
   /* If the type is already signed, just do the simple thing.  */
-  if (! TREE_UNSIGNED (type))
+  if (!TYPE_UNSIGNED (type))
     return size_binop (MINUS_EXPR, arg0, arg1);
 
   ctype = (type == bitsizetype || type == ubitsizetype
@@ -1733,8 +1754,8 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
          TREE_OVERFLOW (t)
            = ((force_fit_type (t,
                                (TREE_INT_CST_HIGH (arg1) < 0
-                                && (TREE_UNSIGNED (type)
-                                   < TREE_UNSIGNED (TREE_TYPE (arg1)))))
+                                && (TYPE_UNSIGNED (type)
+                                   < TYPE_UNSIGNED (TREE_TYPE (arg1)))))
                && ! POINTER_TYPE_P (TREE_TYPE (arg1)))
               || TREE_OVERFLOW (arg1));
          TREE_CONSTANT_OVERFLOW (t)
@@ -1771,6 +1792,10 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
              real_floor (&r, VOIDmode, &x);
              break;
 
+           case FIX_ROUND_EXPR:
+             real_round (&r, VOIDmode, &x);
+             break;
+
            default:
              abort ();
            }
@@ -1857,7 +1882,7 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
 /* Convert expression ARG to type TYPE.  Used by the middle-end for
    simple conversions in preference to calling the front-end's convert.  */
 
-static tree
+tree
 fold_convert (tree type, tree arg)
 {
   tree orig = TREE_TYPE (arg);
@@ -1925,9 +1950,9 @@ fold_convert (tree type, tree arg)
       if (INTEGRAL_TYPE_P (orig)
          || POINTER_TYPE_P (orig)
          || TREE_CODE (orig) == REAL_TYPE)
-       return build (COMPLEX_EXPR, type,
-                     fold_convert (TREE_TYPE (type), arg),
-                     fold_convert (TREE_TYPE (type), integer_zero_node));
+       return build2 (COMPLEX_EXPR, type,
+                      fold_convert (TREE_TYPE (type), arg),
+                      fold_convert (TREE_TYPE (type), integer_zero_node));
       if (TREE_CODE (orig) == COMPLEX_TYPE)
        {
          tree rpart, ipart;
@@ -1936,7 +1961,7 @@ fold_convert (tree type, tree arg)
            {
              rpart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 0));
              ipart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 1));
-             return fold (build (COMPLEX_EXPR, type, rpart, ipart));
+             return fold (build2 (COMPLEX_EXPR, type, rpart, ipart));
            }
 
          arg = save_expr (arg);
@@ -1944,7 +1969,7 @@ fold_convert (tree type, tree arg)
          ipart = fold (build1 (IMAGPART_EXPR, TREE_TYPE (orig), arg));
          rpart = fold_convert (TREE_TYPE (type), rpart);
          ipart = fold_convert (TREE_TYPE (type), ipart);
-         return fold (build (COMPLEX_EXPR, type, rpart, ipart));
+         return fold (build2 (COMPLEX_EXPR, type, rpart, ipart));
        }
     }
   else if (TREE_CODE (type) == VECTOR_TYPE)
@@ -1968,8 +1993,6 @@ fold_convert (tree type, tree arg)
 tree
 non_lvalue (tree x)
 {
-  tree result;
-
   /* These things are certainly not lvalues.  */
   if (TREE_CODE (x) == NON_LVALUE_EXPR
       || TREE_CODE (x) == INTEGER_CST
@@ -1978,9 +2001,7 @@ non_lvalue (tree x)
       || TREE_CODE (x) == ADDR_EXPR)
     return x;
 
-  result = build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
-  TREE_CONSTANT (result) = TREE_CONSTANT (x);
-  return result;
+  return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
 }
 
 /* Nonzero means lvalues are limited to those valid in pedantic ANSI C.
@@ -2116,16 +2137,16 @@ truth_value_p (enum tree_code code)
 \f
 /* Return nonzero if two operands (typically of the same tree node)
    are necessarily equal.  If either argument has side-effects this
-   function returns zero.
+   function returns zero.  FLAGS modifies behaviour as follows:
 
-   If ONLY_CONST is nonzero, only return nonzero for constants.
+   If OEP_ONLY_CONST is set, only return nonzero for constants.
    This function tests whether the operands are indistinguishable;
    it does not test whether they are equal using C's == operation.
    The distinction is important for IEEE floating point, because
    (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and
    (2) two NaNs may be indistinguishable, but NaN!=NaN.
 
-   If ONLY_CONST is zero, a VAR_DECL is considered equal to itself
+   If OEP_ONLY_CONST is unset, a VAR_DECL is considered equal to itself
    even though it may hold multiple values during a function.
    This is because a GCC tree node guarantees that nothing else is
    executed between the evaluation of its "operands" (which may often
@@ -2134,17 +2155,23 @@ truth_value_p (enum tree_code code)
    same value in each operand/subexpression.  Hence a zero value for
    ONLY_CONST assumes isochronic (or instantaneous) tree equivalence.
    If comparing arbitrary expression trees, such as from different
-   statements, ONLY_CONST must usually be nonzero.  */
+   statements, ONLY_CONST must usually be nonzero.
+
+   If OEP_PURE_SAME is set, then pure functions with identical arguments
+   are considered the same.  It is used when the caller has other ways
+   to ensure that global memory is unchanged in between.  */
 
 int
-operand_equal_p (tree arg0, tree arg1, int only_const)
+operand_equal_p (tree arg0, tree arg1, unsigned int flags)
 {
-  tree fndecl;
+  /* If either is ERROR_MARK, they aren't equal.  */
+  if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK)
+    return 0;
 
   /* If both types don't have the same signedness, then we can't consider
      them equal.  We must check this before the STRIP_NOPS calls
      because they may change the signedness of the arguments.  */
-  if (TREE_UNSIGNED (TREE_TYPE (arg0)) != TREE_UNSIGNED (TREE_TYPE (arg1)))
+  if (TYPE_UNSIGNED (TREE_TYPE (arg0)) != TYPE_UNSIGNED (TREE_TYPE (arg1)))
     return 0;
 
   STRIP_NOPS (arg0);
@@ -2165,7 +2192,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
      expressions with side effects that should be treated the same due
      to the only side effects being identical SAVE_EXPR's, that will
      be detected in the recursive calls below.  */
-  if (arg0 == arg1 && ! only_const
+  if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST)
       && (TREE_CODE (arg0) == SAVE_EXPR
          || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
     return 1;
@@ -2198,7 +2225,8 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
          v2 = TREE_VECTOR_CST_ELTS (arg1);
          while (v1 && v2)
            {
-             if (!operand_equal_p (v1, v2, only_const))
+             if (!operand_equal_p (TREE_VALUE (v1), TREE_VALUE (v2),
+                                   flags))
                return 0;
              v1 = TREE_CHAIN (v1);
              v2 = TREE_CHAIN (v2);
@@ -2209,9 +2237,9 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
 
       case COMPLEX_CST:
        return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1),
-                                only_const)
+                                flags)
                && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1),
-                                   only_const));
+                                   flags));
 
       case STRING_CST:
        return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1)
@@ -2226,7 +2254,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
        break;
       }
 
-  if (only_const)
+  if (flags & OEP_ONLY_CONST)
     return 0;
 
   switch (TREE_CODE_CLASS (TREE_CODE (arg0)))
@@ -2234,12 +2262,12 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
     case '1':
       /* Two conversions are equal only if signedness and modes match.  */
       if ((TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == CONVERT_EXPR)
-         && (TREE_UNSIGNED (TREE_TYPE (arg0))
-             != TREE_UNSIGNED (TREE_TYPE (arg1))))
+         && (TYPE_UNSIGNED (TREE_TYPE (arg0))
+             != TYPE_UNSIGNED (TREE_TYPE (arg1))))
        return 0;
 
       return operand_equal_p (TREE_OPERAND (arg0, 0),
-                             TREE_OPERAND (arg1, 0), 0);
+                             TREE_OPERAND (arg1, 0), flags);
 
     case '<':
     case '2':
@@ -2251,9 +2279,9 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
       /* For commutative ops, allow the other order.  */
       return (commutative_tree_code (TREE_CODE (arg0))
              && operand_equal_p (TREE_OPERAND (arg0, 0),
-                                 TREE_OPERAND (arg1, 1), 0)
+                                 TREE_OPERAND (arg1, 1), flags)
              && operand_equal_p (TREE_OPERAND (arg0, 1),
-                                 TREE_OPERAND (arg1, 0), 0));
+                                 TREE_OPERAND (arg1, 0), flags));
 
     case 'r':
       /* If either of the pointer (or reference) expressions we are
@@ -2266,23 +2294,23 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
        {
        case INDIRECT_REF:
          return operand_equal_p (TREE_OPERAND (arg0, 0),
-                                 TREE_OPERAND (arg1, 0), 0);
+                                 TREE_OPERAND (arg1, 0), flags);
 
        case COMPONENT_REF:
        case ARRAY_REF:
        case ARRAY_RANGE_REF:
          return (operand_equal_p (TREE_OPERAND (arg0, 0),
-                                  TREE_OPERAND (arg1, 0), 0)
+                                  TREE_OPERAND (arg1, 0), flags)
                  && operand_equal_p (TREE_OPERAND (arg0, 1),
-                                     TREE_OPERAND (arg1, 1), 0));
+                                     TREE_OPERAND (arg1, 1), flags));
 
        case BIT_FIELD_REF:
          return (operand_equal_p (TREE_OPERAND (arg0, 0),
-                                  TREE_OPERAND (arg1, 0), 0)
+                                  TREE_OPERAND (arg1, 0), flags)
                  && operand_equal_p (TREE_OPERAND (arg0, 1),
-                                     TREE_OPERAND (arg1, 1), 0)
+                                     TREE_OPERAND (arg1, 1), flags)
                  && operand_equal_p (TREE_OPERAND (arg0, 2),
-                                     TREE_OPERAND (arg1, 2), 0));
+                                     TREE_OPERAND (arg1, 2), flags));
        default:
          return 0;
        }
@@ -2293,7 +2321,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
        case ADDR_EXPR:
        case TRUTH_NOT_EXPR:
          return operand_equal_p (TREE_OPERAND (arg0, 0),
-                                 TREE_OPERAND (arg1, 0), 0);
+                                 TREE_OPERAND (arg1, 0), flags);
 
        case RTL_EXPR:
          return rtx_equal_p (RTL_EXPR_RTL (arg0), RTL_EXPR_RTL (arg1));
@@ -2302,14 +2330,18 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
          /* If the CALL_EXPRs call different functions, then they
             clearly can not be equal.  */
          if (! operand_equal_p (TREE_OPERAND (arg0, 0),
-                                TREE_OPERAND (arg1, 0), 0))
+                                TREE_OPERAND (arg1, 0), flags))
            return 0;
 
-         /* Only consider const functions equivalent.  */
-         fndecl = get_callee_fndecl (arg0);
-         if (fndecl == NULL_TREE
-             || ! (flags_from_decl_or_type (fndecl) & ECF_CONST))
-           return 0;
+         {
+           unsigned int cef = call_expr_flags (arg0);
+           if (flags & OEP_PURE_SAME)
+             cef &= ECF_CONST | ECF_PURE;
+           else
+             cef &= ECF_CONST;
+           if (!cef)
+             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
@@ -2318,7 +2350,8 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
          arg1 = TREE_OPERAND (arg1, 1);
          while (arg0 && arg1)
            {
-             if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1), 0))
+             if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1),
+                                    flags))
                return 0;
 
              arg0 = TREE_CHAIN (arg0);
@@ -2334,11 +2367,11 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
        }
 
     case 'd':
-       /* Consider __builtin_sqrt equal to sqrt.  */
-       return TREE_CODE (arg0) == FUNCTION_DECL
-              && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1)
-              && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1)
-              && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1);
+      /* Consider __builtin_sqrt equal to sqrt.  */
+      return (TREE_CODE (arg0) == FUNCTION_DECL
+             && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1)
+             && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1)
+             && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1));
 
     default:
       return 0;
@@ -2391,7 +2424,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 (lang_hooks.types.signed_or_unsigned_type
                               (unsignedp1, TREE_TYPE (primarg1)), primarg1);
 
       if (operand_equal_p (arg0, fold_convert (type, primarg1), 0))
@@ -2525,11 +2558,11 @@ eval_subst (tree arg, tree old0, tree new0, tree old1, tree new1)
                                       old0, new0, old1, new1)));
 
     case '2':
-      return fold (build (code, type,
-                         eval_subst (TREE_OPERAND (arg, 0),
-                                     old0, new0, old1, new1),
-                         eval_subst (TREE_OPERAND (arg, 1),
-                                     old0, new0, old1, new1)));
+      return fold (build2 (code, type,
+                          eval_subst (TREE_OPERAND (arg, 0),
+                                      old0, new0, old1, new1),
+                          eval_subst (TREE_OPERAND (arg, 1),
+                                      old0, new0, old1, new1)));
 
     case 'e':
       switch (code)
@@ -2541,13 +2574,13 @@ eval_subst (tree arg, tree old0, tree new0, tree old1, tree new1)
          return eval_subst (TREE_OPERAND (arg, 1), old0, new0, old1, new1);
 
        case COND_EXPR:
-         return fold (build (code, type,
-                             eval_subst (TREE_OPERAND (arg, 0),
-                                         old0, new0, old1, new1),
-                             eval_subst (TREE_OPERAND (arg, 1),
-                                         old0, new0, old1, new1),
-                             eval_subst (TREE_OPERAND (arg, 2),
-                                         old0, new0, old1, new1)));
+         return fold (build3 (code, type,
+                              eval_subst (TREE_OPERAND (arg, 0),
+                                          old0, new0, old1, new1),
+                              eval_subst (TREE_OPERAND (arg, 1),
+                                          old0, new0, old1, new1),
+                              eval_subst (TREE_OPERAND (arg, 2),
+                                          old0, new0, old1, new1)));
        default:
          break;
        }
@@ -2572,7 +2605,7 @@ eval_subst (tree arg, tree old0, tree new0, tree old1, tree new1)
        else if (arg1 == old1 || operand_equal_p (arg1, old1, 0))
          arg1 = new1;
 
-       return fold (build (code, type, arg0, arg1));
+       return fold (build2 (code, type, arg0, arg1));
       }
 
     default:
@@ -2593,7 +2626,7 @@ omit_one_operand (tree type, tree result, tree omitted)
   tree t = fold_convert (type, result);
 
   if (TREE_SIDE_EFFECTS (omitted))
-    return build (COMPOUND_EXPR, type, omitted, t);
+    return build2 (COMPOUND_EXPR, type, omitted, t);
 
   return non_lvalue (t);
 }
@@ -2606,7 +2639,7 @@ pedantic_omit_one_operand (tree type, tree result, tree omitted)
   tree t = fold_convert (type, result);
 
   if (TREE_SIDE_EFFECTS (omitted))
-    return build (COMPOUND_EXPR, type, omitted, t);
+    return build2 (COMPOUND_EXPR, type, omitted, t);
 
   return pedantic_non_lvalue (t);
 }
@@ -2635,9 +2668,17 @@ invert_truthvalue (tree arg)
          && code != NE_EXPR
          && code != EQ_EXPR)
        return build1 (TRUTH_NOT_EXPR, type, arg);
+      else if (code == UNORDERED_EXPR
+              || code == ORDERED_EXPR
+              || code == UNEQ_EXPR
+              || code == UNLT_EXPR
+              || code == UNLE_EXPR
+              || code == UNGT_EXPR
+              || code == UNGE_EXPR)
+       return build1 (TRUTH_NOT_EXPR, type, arg);
       else
-       return build (invert_tree_comparison (code), type,
-                     TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1));
+       return build2 (invert_tree_comparison (code), type,
+                      TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1));
     }
 
   switch (code)
@@ -2646,14 +2687,14 @@ invert_truthvalue (tree arg)
       return fold_convert (type, build_int_2 (integer_zerop (arg), 0));
 
     case TRUTH_AND_EXPR:
-      return build (TRUTH_OR_EXPR, type,
-                   invert_truthvalue (TREE_OPERAND (arg, 0)),
-                   invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return build2 (TRUTH_OR_EXPR, type,
+                    invert_truthvalue (TREE_OPERAND (arg, 0)),
+                    invert_truthvalue (TREE_OPERAND (arg, 1)));
 
     case TRUTH_OR_EXPR:
-      return build (TRUTH_AND_EXPR, type,
-                   invert_truthvalue (TREE_OPERAND (arg, 0)),
-                   invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return build2 (TRUTH_AND_EXPR, type,
+                    invert_truthvalue (TREE_OPERAND (arg, 0)),
+                    invert_truthvalue (TREE_OPERAND (arg, 1)));
 
     case TRUTH_XOR_EXPR:
       /* Here we can invert either operand.  We invert the first operand
@@ -2662,44 +2703,42 @@ invert_truthvalue (tree arg)
         negation of the second operand.  */
 
       if (TREE_CODE (TREE_OPERAND (arg, 1)) == TRUTH_NOT_EXPR)
-       return build (TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0),
-                     TREE_OPERAND (TREE_OPERAND (arg, 1), 0));
+       return build2 (TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0),
+                      TREE_OPERAND (TREE_OPERAND (arg, 1), 0));
       else
-       return build (TRUTH_XOR_EXPR, type,
-                     invert_truthvalue (TREE_OPERAND (arg, 0)),
-                     TREE_OPERAND (arg, 1));
+       return build2 (TRUTH_XOR_EXPR, type,
+                      invert_truthvalue (TREE_OPERAND (arg, 0)),
+                      TREE_OPERAND (arg, 1));
 
     case TRUTH_ANDIF_EXPR:
-      return build (TRUTH_ORIF_EXPR, type,
-                   invert_truthvalue (TREE_OPERAND (arg, 0)),
-                   invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return build2 (TRUTH_ORIF_EXPR, type,
+                    invert_truthvalue (TREE_OPERAND (arg, 0)),
+                    invert_truthvalue (TREE_OPERAND (arg, 1)));
 
     case TRUTH_ORIF_EXPR:
-      return build (TRUTH_ANDIF_EXPR, type,
-                   invert_truthvalue (TREE_OPERAND (arg, 0)),
-                   invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return build2 (TRUTH_ANDIF_EXPR, type,
+                    invert_truthvalue (TREE_OPERAND (arg, 0)),
+                    invert_truthvalue (TREE_OPERAND (arg, 1)));
 
     case TRUTH_NOT_EXPR:
       return TREE_OPERAND (arg, 0);
 
     case COND_EXPR:
-      return build (COND_EXPR, type, TREE_OPERAND (arg, 0),
-                   invert_truthvalue (TREE_OPERAND (arg, 1)),
-                   invert_truthvalue (TREE_OPERAND (arg, 2)));
+      return build3 (COND_EXPR, type, TREE_OPERAND (arg, 0),
+                    invert_truthvalue (TREE_OPERAND (arg, 1)),
+                    invert_truthvalue (TREE_OPERAND (arg, 2)));
 
     case COMPOUND_EXPR:
-      return build (COMPOUND_EXPR, type, TREE_OPERAND (arg, 0),
-                   invert_truthvalue (TREE_OPERAND (arg, 1)));
-
-    case WITH_RECORD_EXPR:
-      return build (WITH_RECORD_EXPR, type,
-                   invert_truthvalue (TREE_OPERAND (arg, 0)),
-                   TREE_OPERAND (arg, 1));
+      return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg, 0),
+                    invert_truthvalue (TREE_OPERAND (arg, 1)));
 
     case NON_LVALUE_EXPR:
       return invert_truthvalue (TREE_OPERAND (arg, 0));
 
     case NOP_EXPR:
+      if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
+        break;
+
     case CONVERT_EXPR:
     case FLOAT_EXPR:
       return build1 (TREE_CODE (arg), type,
@@ -2708,8 +2747,8 @@ invert_truthvalue (tree arg)
     case BIT_AND_EXPR:
       if (!integer_onep (TREE_OPERAND (arg, 1)))
        break;
-      return build (EQ_EXPR, type, arg,
-                   fold_convert (type, integer_zero_node));
+      return build2 (EQ_EXPR, type, arg,
+                    fold_convert (type, integer_zero_node));
 
     case SAVE_EXPR:
       return build1 (TRUTH_NOT_EXPR, type, arg);
@@ -2774,8 +2813,8 @@ distribute_bit_expr (enum tree_code code, tree type, tree arg0, tree arg1)
   else
     return 0;
 
-  return fold (build (TREE_CODE (arg0), type, common,
-                     fold (build (code, type, left, right))));
+  return fold (build2 (TREE_CODE (arg0), type, common,
+                      fold (build2 (code, type, left, right))));
 }
 \f
 /* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
@@ -2785,10 +2824,10 @@ static tree
 make_bit_field_ref (tree inner, tree type, int bitsize, int bitpos,
                    int unsignedp)
 {
-  tree result = build (BIT_FIELD_REF, type, inner,
-                      size_int (bitsize), bitsize_int (bitpos));
+  tree result = build3 (BIT_FIELD_REF, type, inner,
+                       size_int (bitsize), bitsize_int (bitpos));
 
-  TREE_UNSIGNED (result) = unsignedp;
+  BIT_FIELD_REF_UNSIGNED (result) = unsignedp;
 
   return result;
 }
@@ -2864,8 +2903,8 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
 
   /* Set signed and unsigned types of the precision of this mode for the
      shifts below.  */
-  signed_type = (*lang_hooks.types.type_for_mode) (nmode, 0);
-  unsigned_type = (*lang_hooks.types.type_for_mode) (nmode, 1);
+  signed_type = lang_hooks.types.type_for_mode (nmode, 0);
+  unsigned_type = lang_hooks.types.type_for_mode (nmode, 1);
 
   /* Compute the bit position and size for the new reference and our offset
      within it. If the new reference is the same size as the original, we
@@ -2891,15 +2930,15 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
   if (! const_p)
     /* If not comparing with constant, just rework the comparison
        and return.  */
-    return build (code, compare_type,
-                 build (BIT_AND_EXPR, unsigned_type,
-                        make_bit_field_ref (linner, unsigned_type,
-                                            nbitsize, nbitpos, 1),
-                        mask),
-                 build (BIT_AND_EXPR, unsigned_type,
-                        make_bit_field_ref (rinner, unsigned_type,
-                                            nbitsize, nbitpos, 1),
-                        mask));
+    return build2 (code, compare_type,
+                  build2 (BIT_AND_EXPR, unsigned_type,
+                          make_bit_field_ref (linner, unsigned_type,
+                                              nbitsize, nbitpos, 1),
+                          mask),
+                  build2 (BIT_AND_EXPR, unsigned_type,
+                          make_bit_field_ref (rinner, unsigned_type,
+                                              nbitsize, nbitpos, 1),
+                          mask));
 
   /* Otherwise, we are handling the constant case. See if the constant is too
      big for the field.  Warn and return a tree of for 0 (false) if so.  We do
@@ -2960,9 +2999,9 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
                                        size_int (lbitpos), 0),
                           mask, 0));
 
-  return build (code, compare_type,
-               build (BIT_AND_EXPR, unsigned_type, lhs, mask),
-               rhs);
+  return build2 (code, compare_type,
+                build2 (BIT_AND_EXPR, unsigned_type, lhs, mask),
+                rhs);
 }
 \f
 /* Subroutine for fold_truthop: decode a field reference.
@@ -3035,10 +3074,10 @@ decode_field_reference (tree exp, HOST_WIDE_INT *pbitsize,
      the outer type, then the outer type gives the signedness. Otherwise
      (in case of a small bitfield) the signedness is unchanged.  */
   if (outer_type && *pbitsize == tree_low_cst (TYPE_SIZE (outer_type), 1))
-    *punsignedp = TREE_UNSIGNED (outer_type);
+    *punsignedp = TYPE_UNSIGNED (outer_type);
 
   /* Compute the mask to access the bitfield.  */
-  unsigned_type = (*lang_hooks.types.type_for_size) (*pbitsize, 1);
+  unsigned_type = lang_hooks.types.type_for_size (*pbitsize, 1);
   precision = TYPE_PRECISION (unsigned_type);
 
   mask = build_int_2 (~0, ~0);
@@ -3049,8 +3088,8 @@ decode_field_reference (tree exp, HOST_WIDE_INT *pbitsize,
 
   /* Merge it with the mask we found in the BIT_AND_EXPR, if any.  */
   if (and_mask != 0)
-    mask = fold (build (BIT_AND_EXPR, unsigned_type,
-                       fold_convert (unsigned_type, and_mask), mask));
+    mask = fold (build2 (BIT_AND_EXPR, unsigned_type,
+                        fold_convert (unsigned_type, and_mask), mask));
 
   *pmask = mask;
   *pand_mask = and_mask;
@@ -3068,7 +3107,7 @@ all_ones_mask_p (tree mask, int size)
   tree tmask;
 
   tmask = build_int_2 (~0, ~0);
-  TREE_TYPE (tmask) = (*lang_hooks.types.signed_type) (type);
+  TREE_TYPE (tmask) = lang_hooks.types.signed_type (type);
   force_fit_type (tmask, 0);
   return
     tree_int_cst_equal (mask,
@@ -3215,8 +3254,8 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
 
   if (arg0 != 0 && arg1 != 0)
     {
-      tem = fold (build (code, type != 0 ? type : TREE_TYPE (arg0),
-                        arg0, fold_convert (TREE_TYPE (arg0), arg1)));
+      tem = fold (build2 (code, type != 0 ? type : TREE_TYPE (arg0),
+                         arg0, fold_convert (TREE_TYPE (arg0), arg1)));
       STRIP_NOPS (tem);
       return TREE_CODE (tem) == INTEGER_CST ? tem : 0;
     }
@@ -3355,7 +3394,7 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
             greater than or equal to zero.  We base the range tests we make
             on that fact, so we record it here so we can parse existing
             range tests.  */
-         if (TREE_UNSIGNED (type) && (low == 0 || high == 0))
+         if (TYPE_UNSIGNED (type) && (low == 0 || high == 0))
            {
              if (! merge_ranges (&n_in_p, &n_low, &n_high, in_p, low, high,
                                  1, fold_convert (type, integer_zero_node),
@@ -3391,8 +3430,8 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
 
        case BIT_NOT_EXPR:
          /* ~ X -> -X - 1  */
-         exp = build (MINUS_EXPR, type, negate_expr (arg0),
-                      fold_convert (type, integer_one_node));
+         exp = build2 (MINUS_EXPR, type, negate_expr (arg0),
+                       fold_convert (type, integer_one_node));
          continue;
 
        case PLUS_EXPR:  case MINUS_EXPR:
@@ -3459,9 +3498,9 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
 
             So we have to make sure that the original unsigned value will
             be interpreted as positive.  */
-         if (TREE_UNSIGNED (type) && ! TREE_UNSIGNED (TREE_TYPE (exp)))
+         if (TYPE_UNSIGNED (type) && ! TYPE_UNSIGNED (TREE_TYPE (exp)))
            {
-             tree equiv_type = (*lang_hooks.types.type_for_mode)
+             tree equiv_type = lang_hooks.types.type_for_mode
                (TYPE_MODE (type), 1);
              tree high_positive;
 
@@ -3473,11 +3512,11 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
                  : TYPE_MAX_VALUE (type);
 
              if (TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (exp)))
-               high_positive = fold (build (RSHIFT_EXPR, type,
-                                            fold_convert (type,
-                                                          high_positive),
-                                            fold_convert (type,
-                                                          integer_one_node)));
+               high_positive = fold (build2 (RSHIFT_EXPR, type,
+                                             fold_convert (type,
+                                                           high_positive),
+                                             fold_convert (type,
+                                                           integer_one_node)));
 
              /* If the low bound is specified, "and" the range with the
                 range for which the original unsigned value will be
@@ -3550,19 +3589,19 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
     return fold_convert (type, integer_one_node);
 
   if (low == 0)
-    return fold (build (LE_EXPR, type, exp, high));
+    return fold (build2 (LE_EXPR, type, exp, high));
 
   if (high == 0)
-    return fold (build (GE_EXPR, type, exp, low));
+    return fold (build2 (GE_EXPR, type, exp, low));
 
   if (operand_equal_p (low, high, 0))
-    return fold (build (EQ_EXPR, type, exp, low));
+    return fold (build2 (EQ_EXPR, type, exp, low));
 
   if (integer_zerop (low))
     {
-      if (! TREE_UNSIGNED (etype))
+      if (! TYPE_UNSIGNED (etype))
        {
-         etype = (*lang_hooks.types.unsigned_type) (etype);
+         etype = lang_hooks.types.unsigned_type (etype);
          high = fold_convert (etype, high);
          exp = fold_convert (etype, exp);
        }
@@ -3590,20 +3629,20 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
 
       if (TREE_INT_CST_HIGH (high) == hi && TREE_INT_CST_LOW (high) == lo)
        {
-         if (TREE_UNSIGNED (etype))
+         if (TYPE_UNSIGNED (etype))
            {
-             etype = (*lang_hooks.types.signed_type) (etype);
+             etype = lang_hooks.types.signed_type (etype);
              exp = fold_convert (etype, exp);
            }
-         return fold (build (GT_EXPR, type, exp,
-                             fold_convert (etype, integer_zero_node)));
+         return fold (build2 (GT_EXPR, type, exp,
+                              fold_convert (etype, integer_zero_node)));
        }
     }
 
   if (0 != (value = const_binop (MINUS_EXPR, high, low, 0))
       && ! TREE_OVERFLOW (value))
     return build_range_check (type,
-                             fold (build (MINUS_EXPR, etype, exp, low)),
+                             fold (build2 (MINUS_EXPR, etype, exp, low)),
                              1, fold_convert (etype, integer_zero_node),
                              value);
 
@@ -3792,12 +3831,12 @@ fold_range_test (tree exp)
         unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in
         which cases we can't do this.  */
       if (simple_operand_p (lhs))
-       return build (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
-                     ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
-                     TREE_TYPE (exp), TREE_OPERAND (exp, 0),
-                     TREE_OPERAND (exp, 1));
+       return build2 (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
+                      ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+                      TREE_TYPE (exp), TREE_OPERAND (exp, 0),
+                      TREE_OPERAND (exp, 1));
 
-      else if ((*lang_hooks.decls.global_bindings_p) () == 0
+      else if (lang_hooks.decls.global_bindings_p () == 0
               && ! CONTAINS_PLACEHOLDER_P (lhs))
        {
          tree common = save_expr (lhs);
@@ -3808,9 +3847,9 @@ fold_range_test (tree exp)
              && (0 != (rhs = build_range_check (TREE_TYPE (exp), common,
                                                 or_op ? ! in1_p : in1_p,
                                                 low1, high1))))
-           return build (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
-                         ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
-                         TREE_TYPE (exp), lhs, rhs);
+           return build2 (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
+                          ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+                          TREE_TYPE (exp), lhs, rhs);
        }
     }
 
@@ -3844,8 +3883,8 @@ unextend (tree c, int p, int unsignedp, tree mask)
      do the type conversion here.  At this point, the constant is either
      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 (TREE_UNSIGNED (type))
-    temp = fold_convert ((*lang_hooks.types.signed_type) (type), temp);
+  if (TYPE_UNSIGNED (type))
+    temp = fold_convert (lang_hooks.types.signed_type (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);
@@ -3853,7 +3892,7 @@ unextend (tree c, int p, int unsignedp, tree mask)
     temp = const_binop (BIT_AND_EXPR, temp,
                        fold_convert (TREE_TYPE (c), mask), 0);
   /* If necessary, convert the type back to match the type of C.  */
-  if (TREE_UNSIGNED (type))
+  if (TYPE_UNSIGNED (type))
     temp = fold_convert (type, temp);
 
   return fold_convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0));
@@ -3924,10 +3963,16 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
   rcode = TREE_CODE (rhs);
 
   if (lcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (lhs, 1)))
-    lcode = NE_EXPR, lhs = build (NE_EXPR, truth_type, lhs, integer_zero_node);
+    {
+      lhs = build2 (NE_EXPR, truth_type, lhs, integer_zero_node);
+      lcode = NE_EXPR;
+    }
 
   if (rcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (rhs, 1)))
-    rcode = NE_EXPR, rhs = build (NE_EXPR, truth_type, rhs, integer_zero_node);
+    {
+      rhs = build2 (NE_EXPR, truth_type, rhs, integer_zero_node);
+      rcode = NE_EXPR;
+    }
 
   if (TREE_CODE_CLASS (lcode) != '<' || TREE_CODE_CLASS (rcode) != '<')
     return 0;
@@ -3978,8 +4023,8 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
       else if (compcode == COMPCODE_FALSE)
        return fold_convert (truth_type, integer_zero_node);
       else if (compcode != -1)
-       return build (compcode_to_comparison (compcode),
-                     truth_type, ll_arg, lr_arg);
+       return build2 (compcode_to_comparison (compcode),
+                      truth_type, ll_arg, lr_arg);
     }
 
   /* If the RHS can be evaluated unconditionally and its operands are
@@ -3998,22 +4043,22 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
          && lcode == NE_EXPR && integer_zerop (lr_arg)
          && rcode == NE_EXPR && integer_zerop (rr_arg)
          && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg))
-       return build (NE_EXPR, truth_type,
-                     build (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
-                            ll_arg, rl_arg),
-                     integer_zero_node);
+       return build2 (NE_EXPR, truth_type,
+                      build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
+                              ll_arg, rl_arg),
+                      integer_zero_node);
 
       /* Convert (a == 0) && (b == 0) into (a | b) == 0.  */
       if (code == TRUTH_AND_EXPR
          && lcode == EQ_EXPR && integer_zerop (lr_arg)
          && rcode == EQ_EXPR && integer_zerop (rr_arg)
          && TREE_TYPE (ll_arg) == TREE_TYPE (rl_arg))
-       return build (EQ_EXPR, truth_type,
-                     build (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
-                            ll_arg, rl_arg),
-                     integer_zero_node);
+       return build2 (EQ_EXPR, truth_type,
+                      build2 (BIT_IOR_EXPR, TREE_TYPE (ll_arg),
+                              ll_arg, rl_arg),
+                      integer_zero_node);
 
-      return build (code, truth_type, lhs, rhs);
+      return build2 (code, truth_type, lhs, rhs);
     }
 
   /* See if the comparisons can be merged.  Then get all the parameters for
@@ -4091,7 +4136,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
 
   /* After this point all optimizations will generate bit-field
      references, which we might not want.  */
-  if (! (*lang_hooks.can_use_bit_fields_p) ())
+  if (! lang_hooks.can_use_bit_fields_p ())
     return 0;
 
   /* See if we can find a mode that contains both fields being compared on
@@ -4107,7 +4152,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
 
   lnbitsize = GET_MODE_BITSIZE (lnmode);
   lnbitpos = first_bit & ~ (lnbitsize - 1);
-  lntype = (*lang_hooks.types.type_for_size) (lnbitsize, 1);
+  lntype = lang_hooks.types.type_for_size (lnbitsize, 1);
   xll_bitpos = ll_bitpos - lnbitpos, xrl_bitpos = rl_bitpos - lnbitpos;
 
   if (BYTES_BIG_ENDIAN)
@@ -4178,7 +4223,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
 
       rnbitsize = GET_MODE_BITSIZE (rnmode);
       rnbitpos = first_bit & ~ (rnbitsize - 1);
-      rntype = (*lang_hooks.types.type_for_size) (rnbitsize, 1);
+      rntype = lang_hooks.types.type_for_size (rnbitsize, 1);
       xlr_bitpos = lr_bitpos - rnbitpos, xrr_bitpos = rr_bitpos - rnbitpos;
 
       if (BYTES_BIG_ENDIAN)
@@ -4204,14 +4249,14 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
          lhs = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos,
                                    ll_unsignedp || rl_unsignedp);
          if (! all_ones_mask_p (ll_mask, lnbitsize))
-           lhs = build (BIT_AND_EXPR, lntype, lhs, ll_mask);
+           lhs = build2 (BIT_AND_EXPR, lntype, lhs, ll_mask);
 
          rhs = make_bit_field_ref (lr_inner, rntype, rnbitsize, rnbitpos,
                                    lr_unsignedp || rr_unsignedp);
          if (! all_ones_mask_p (lr_mask, rnbitsize))
-           rhs = build (BIT_AND_EXPR, rntype, rhs, lr_mask);
+           rhs = build2 (BIT_AND_EXPR, rntype, rhs, lr_mask);
 
-         return build (wanted_code, truth_type, lhs, rhs);
+         return build2 (wanted_code, truth_type, lhs, rhs);
        }
 
       /* There is still another way we can do something:  If both pairs of
@@ -4257,12 +4302,12 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
            }
 
          if (! all_ones_mask_p (ll_mask, ll_bitsize + rl_bitsize))
-           lhs = build (BIT_AND_EXPR, type, lhs, ll_mask);
+           lhs = build2 (BIT_AND_EXPR, type, lhs, ll_mask);
 
          if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize))
-           rhs = build (BIT_AND_EXPR, type, rhs, lr_mask);
+           rhs = build2 (BIT_AND_EXPR, type, rhs, lr_mask);
 
-         return build (wanted_code, truth_type, lhs, rhs);
+         return build2 (wanted_code, truth_type, lhs, rhs);
        }
 
       return 0;
@@ -4298,10 +4343,10 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
 
   ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
   if (! all_ones_mask_p (ll_mask, lnbitsize))
-    result = build (BIT_AND_EXPR, lntype, result, ll_mask);
+    result = build2 (BIT_AND_EXPR, lntype, result, ll_mask);
 
-  return build (wanted_code, truth_type, result,
-               const_binop (BIT_IOR_EXPR, l_const, r_const, 0));
+  return build2 (wanted_code, truth_type, result,
+                const_binop (BIT_IOR_EXPR, l_const, r_const, 0));
 }
 \f
 /* Optimize T, which is a comparison of a MIN_EXPR or MAX_EXPR with a
@@ -4345,20 +4390,20 @@ optimize_minmax_comparison (tree t)
 
     case GE_EXPR:
       return
-       fold (build (TRUTH_ORIF_EXPR, type,
-                    optimize_minmax_comparison
-                    (build (EQ_EXPR, type, arg0, comp_const)),
-                    optimize_minmax_comparison
-                    (build (GT_EXPR, type, arg0, comp_const))));
+       fold (build2 (TRUTH_ORIF_EXPR, type,
+                     optimize_minmax_comparison
+                     (build2 (EQ_EXPR, type, arg0, comp_const)),
+                     optimize_minmax_comparison
+                     (build2 (GT_EXPR, type, arg0, comp_const))));
 
     case EQ_EXPR:
       if (op_code == MAX_EXPR && consts_equal)
        /* MAX (X, 0) == 0  ->  X <= 0  */
-       return fold (build (LE_EXPR, type, inner, comp_const));
+       return fold (build2 (LE_EXPR, type, inner, comp_const));
 
       else if (op_code == MAX_EXPR && consts_lt)
        /* MAX (X, 0) == 5  ->  X == 5   */
-       return fold (build (EQ_EXPR, type, inner, comp_const));
+       return fold (build2 (EQ_EXPR, type, inner, comp_const));
 
       else if (op_code == MAX_EXPR)
        /* MAX (X, 0) == -1  ->  false  */
@@ -4366,7 +4411,7 @@ optimize_minmax_comparison (tree t)
 
       else if (consts_equal)
        /* MIN (X, 0) == 0  ->  X >= 0  */
-       return fold (build (GE_EXPR, type, inner, comp_const));
+       return fold (build2 (GE_EXPR, type, inner, comp_const));
 
       else if (consts_lt)
        /* MIN (X, 0) == 5  ->  false  */
@@ -4374,13 +4419,13 @@ optimize_minmax_comparison (tree t)
 
       else
        /* MIN (X, 0) == -1  ->  X == -1  */
-       return fold (build (EQ_EXPR, type, inner, comp_const));
+       return fold (build2 (EQ_EXPR, type, inner, comp_const));
 
     case GT_EXPR:
       if (op_code == MAX_EXPR && (consts_equal || consts_lt))
        /* MAX (X, 0) > 0  ->  X > 0
           MAX (X, 0) > 5  ->  X > 5  */
-       return fold (build (GT_EXPR, type, inner, comp_const));
+       return fold (build2 (GT_EXPR, type, inner, comp_const));
 
       else if (op_code == MAX_EXPR)
        /* MAX (X, 0) > -1  ->  true  */
@@ -4393,7 +4438,7 @@ optimize_minmax_comparison (tree t)
 
       else
        /* MIN (X, 0) > -1  ->  X > -1  */
-       return fold (build (GT_EXPR, type, inner, comp_const));
+       return fold (build2 (GT_EXPR, type, inner, comp_const));
 
     default:
       return t;
@@ -4482,7 +4527,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
           || TREE_CODE_CLASS (TREE_CODE (op0)) == 'e')
          /* ... and is unsigned, and its type is smaller than ctype,
             then we cannot pass through as widening.  */
-         && ((TREE_UNSIGNED (TREE_TYPE (op0))
+         && ((TYPE_UNSIGNED (TREE_TYPE (op0))
               && ! (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
                     && TYPE_IS_SIZETYPE (TREE_TYPE (op0)))
               && (GET_MODE_SIZE (TYPE_MODE (ctype))
@@ -4494,8 +4539,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
              /* ... or signedness changes for division or modulus,
                 then we cannot pass through this conversion.  */
              || (code != MULT_EXPR
-                 && (TREE_UNSIGNED (ctype)
-                     != TREE_UNSIGNED (TREE_TYPE (op0))))))
+                 && (TYPE_UNSIGNED (ctype)
+                     != TYPE_UNSIGNED (TREE_TYPE (op0))))))
        break;
 
       /* Pass the constant down and see if we can make a simplification.  If
@@ -4518,7 +4563,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
     case MIN_EXPR:  case MAX_EXPR:
       /* If widening the type changes the signedness, then we can't perform
         this optimization as that changes the result.  */
-      if (TREE_UNSIGNED (ctype) != TREE_UNSIGNED (type))
+      if (TYPE_UNSIGNED (ctype) != TYPE_UNSIGNED (type))
        break;
 
       /* MIN (a, b) / 5 -> MIN (a / 5, b / 5)  */
@@ -4528,17 +4573,11 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
          if (tree_int_cst_sgn (c) < 0)
            tcode = (tcode == MIN_EXPR ? MAX_EXPR : MIN_EXPR);
 
-         return fold (build (tcode, ctype, fold_convert (ctype, t1),
-                             fold_convert (ctype, t2)));
+         return fold (build2 (tcode, ctype, fold_convert (ctype, t1),
+                              fold_convert (ctype, t2)));
        }
       break;
 
-    case WITH_RECORD_EXPR:
-      if ((t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code, wide_type)) != 0)
-       return build (WITH_RECORD_EXPR, TREE_TYPE (t1), t1,
-                     TREE_OPERAND (t, 1));
-      break;
-
     case LSHIFT_EXPR:  case RSHIFT_EXPR:
       /* If the second operand is constant, this is a multiplication
         or floor division, by a power of two, so we can treat it that
@@ -4553,9 +4592,9 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
                                                   size_one_node,
                                                   op1, 0)))
          && ! TREE_OVERFLOW (t1))
-       return extract_muldiv (build (tcode == LSHIFT_EXPR
-                                     ? MULT_EXPR : FLOOR_DIV_EXPR,
-                                     ctype, fold_convert (ctype, op0), t1),
+       return extract_muldiv (build2 (tcode == LSHIFT_EXPR
+                                      ? MULT_EXPR : FLOOR_DIV_EXPR,
+                                      ctype, fold_convert (ctype, op0), t1),
                               c, code, wide_type);
       break;
 
@@ -4572,8 +4611,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
                 are divisible by c.  */
              || (multiple_of_p (ctype, op0, c)
                  && multiple_of_p (ctype, op1, c))))
-       return fold (build (tcode, ctype, fold_convert (ctype, t1),
-                           fold_convert (ctype, t2)));
+       return fold (build2 (tcode, ctype, fold_convert (ctype, t1),
+                            fold_convert (ctype, t2)));
 
       /* If this was a subtraction, negate OP1 and set it to be an addition.
         This simplifies the logic below.  */
@@ -4615,7 +4654,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
       /* If we have an unsigned type is not a sizetype, we cannot widen
         the operation since it will change the result if the original
         computation overflowed.  */
-      if (TREE_UNSIGNED (ctype)
+      if (TYPE_UNSIGNED (ctype)
          && ! (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype))
          && ctype != type)
        break;
@@ -4623,17 +4662,17 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
       /* If we were able to eliminate our operation from the first side,
         apply our operation to the second side and reform the PLUS.  */
       if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR))
-       return fold (build (tcode, ctype, fold_convert (ctype, t1), op1));
+       return fold (build2 (tcode, ctype, fold_convert (ctype, t1), op1));
 
       /* The last case is if we are a multiply.  In that case, we can
         apply the distributive law to commute the multiply and addition
         if the multiplication of the constants doesn't overflow.  */
       if (code == MULT_EXPR)
-       return fold (build (tcode, ctype,
-                           fold (build (code, ctype,
-                                        fold_convert (ctype, op0),
-                                        fold_convert (ctype, c))),
-                           op1));
+       return fold (build2 (tcode, ctype,
+                            fold (build2 (code, ctype,
+                                          fold_convert (ctype, op0),
+                                          fold_convert (ctype, c))),
+                            op1));
 
       break;
 
@@ -4655,12 +4694,12 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
         do something only if the second operand is a constant.  */
       if (same_p
          && (t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
-       return fold (build (tcode, ctype, fold_convert (ctype, t1),
-                           fold_convert (ctype, op1)));
+       return fold (build2 (tcode, ctype, fold_convert (ctype, t1),
+                            fold_convert (ctype, op1)));
       else if (tcode == MULT_EXPR && code == MULT_EXPR
               && (t1 = extract_muldiv (op1, c, code, wide_type)) != 0)
-       return fold (build (tcode, ctype, fold_convert (ctype, op0),
-                           fold_convert (ctype, t1)));
+       return fold (build2 (tcode, ctype, fold_convert (ctype, op0),
+                            fold_convert (ctype, t1)));
       else if (TREE_CODE (op1) != INTEGER_CST)
        return 0;
 
@@ -4670,7 +4709,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
          && 0 != (t1 = const_binop (MULT_EXPR, fold_convert (ctype, op1),
                                     fold_convert (ctype, c), 0))
          && ! TREE_OVERFLOW (t1))
-       return fold (build (tcode, ctype, fold_convert (ctype, op0), t1));
+       return fold (build2 (tcode, ctype, fold_convert (ctype, op0), t1));
 
       /* If these operations "cancel" each other, we have the main
         optimizations of this pass, which occur when either constant is a
@@ -4680,7 +4719,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
         If we have an unsigned type that is not a sizetype, we cannot do
         this since it will change the result if the original computation
         overflowed.  */
-      if ((! TREE_UNSIGNED (ctype)
+      if ((! TYPE_UNSIGNED (ctype)
           || (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)))
          && ! flag_wrapv
          && ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
@@ -4689,15 +4728,15 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
                  && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR)))
        {
          if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
-           return fold (build (tcode, ctype, fold_convert (ctype, op0),
-                               fold_convert (ctype,
-                                             const_binop (TRUNC_DIV_EXPR,
-                                                          op1, c, 0))));
+           return fold (build2 (tcode, ctype, fold_convert (ctype, op0),
+                                fold_convert (ctype,
+                                              const_binop (TRUNC_DIV_EXPR,
+                                                           op1, c, 0))));
          else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0)))
-           return fold (build (code, ctype, fold_convert (ctype, op0),
-                               fold_convert (ctype,
-                                             const_binop (TRUNC_DIV_EXPR,
-                                                          c, op1, 0))));
+           return fold (build2 (code, ctype, fold_convert (ctype, op0),
+                                fold_convert (ctype,
+                                              const_binop (TRUNC_DIV_EXPR,
+                                                           c, op1, 0))));
        }
       break;
 
@@ -4708,40 +4747,6 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
   return 0;
 }
 \f
-/* If T contains a COMPOUND_EXPR which was inserted merely to evaluate
-   S, a SAVE_EXPR, return the expression actually being evaluated.   Note
-   that we may sometimes modify the tree.  */
-
-static tree
-strip_compound_expr (tree t, tree s)
-{
-  enum tree_code code = TREE_CODE (t);
-
-  /* See if this is the COMPOUND_EXPR we want to eliminate.  */
-  if (code == COMPOUND_EXPR && TREE_CODE (TREE_OPERAND (t, 0)) == CONVERT_EXPR
-      && TREE_OPERAND (TREE_OPERAND (t, 0), 0) == s)
-    return TREE_OPERAND (t, 1);
-
-  /* See if this is a COND_EXPR or a simple arithmetic operator.   We
-     don't bother handling any other types.  */
-  else if (code == COND_EXPR)
-    {
-      TREE_OPERAND (t, 0) = strip_compound_expr (TREE_OPERAND (t, 0), s);
-      TREE_OPERAND (t, 1) = strip_compound_expr (TREE_OPERAND (t, 1), s);
-      TREE_OPERAND (t, 2) = strip_compound_expr (TREE_OPERAND (t, 2), s);
-    }
-  else if (TREE_CODE_CLASS (code) == '1')
-    TREE_OPERAND (t, 0) = strip_compound_expr (TREE_OPERAND (t, 0), s);
-  else if (TREE_CODE_CLASS (code) == '<'
-          || TREE_CODE_CLASS (code) == '2')
-    {
-      TREE_OPERAND (t, 0) = strip_compound_expr (TREE_OPERAND (t, 0), s);
-      TREE_OPERAND (t, 1) = strip_compound_expr (TREE_OPERAND (t, 1), s);
-    }
-
-  return t;
-}
-\f
 /* Return a node which has the indicated constant VALUE (either 0 or
    1), and is of the indicated TYPE.  */
 
@@ -4751,8 +4756,8 @@ constant_boolean_node (int value, tree type)
   if (type == integer_type_node)
     return value ? integer_one_node : integer_zero_node;
   else if (TREE_CODE (type) == BOOLEAN_TYPE)
-    return (*lang_hooks.truthvalue_conversion) (value ? integer_one_node :
-                                               integer_zero_node);
+    return lang_hooks.truthvalue_conversion (value ? integer_one_node
+                                                  : integer_zero_node);
   else
     {
       tree t = build_int_2 (value, 0);
@@ -4762,32 +4767,14 @@ constant_boolean_node (int value, tree type)
     }
 }
 
-/* Utility function for the following routine, to see how complex a nesting of
-   COND_EXPRs can be.  EXPR is the expression and LIMIT is a count beyond which
-   we don't care (to avoid spending too much time on complex expressions.).  */
-
-static int
-count_cond (tree expr, int lim)
-{
-  int ctrue, cfalse;
-
-  if (TREE_CODE (expr) != COND_EXPR)
-    return 0;
-  else if (lim <= 0)
-    return 0;
-
-  ctrue = count_cond (TREE_OPERAND (expr, 1), lim - 1);
-  cfalse = count_cond (TREE_OPERAND (expr, 2), lim - 1 - ctrue);
-  return MIN (lim, 1 + ctrue + cfalse);
-}
-
 /* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'.
    Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'.  Here
    CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)'
    expression, and ARG to `a'.  If COND_FIRST_P is nonzero, then the
    COND is the first argument to CODE; otherwise (as in the example
    given here), it is the second argument.  TYPE is the type of the
-   original expression.  */
+   original expression.  Return NULL_TREE if no simplification is
+   possible.  */
 
 static tree
 fold_binary_op_with_conditional_arg (enum tree_code code, tree type,
@@ -4796,39 +4783,12 @@ fold_binary_op_with_conditional_arg (enum tree_code code, tree type,
   tree test, true_value, false_value;
   tree lhs = NULL_TREE;
   tree rhs = NULL_TREE;
-  /* In the end, we'll produce a COND_EXPR.  Both arms of the
-     conditional expression will be binary operations.  The left-hand
-     side of the expression to be executed if the condition is true
-     will be pointed to by TRUE_LHS.  Similarly, the right-hand side
-     of the expression to be executed if the condition is true will be
-     pointed to by TRUE_RHS.  FALSE_LHS and FALSE_RHS are analogous --
-     but apply to the expression to be executed if the conditional is
-     false.  */
-  tree *true_lhs;
-  tree *true_rhs;
-  tree *false_lhs;
-  tree *false_rhs;
-  /* These are the codes to use for the left-hand side and right-hand
-     side of the COND_EXPR.  Normally, they are the same as CODE.  */
-  enum tree_code lhs_code = code;
-  enum tree_code rhs_code = code;
-  /* And these are the types of the expressions.  */
-  tree lhs_type = type;
-  tree rhs_type = type;
-  int save = 0;
-
-  if (cond_first_p)
-    {
-      true_rhs = false_rhs = &arg;
-      true_lhs = &true_value;
-      false_lhs = &false_value;
-    }
-  else
-    {
-      true_lhs = false_lhs = &arg;
-      true_rhs = &true_value;
-      false_rhs = &false_value;
-    }
+
+  /* This transformation is only worthwhile if we don't have to wrap
+     arg in a SAVE_EXPR, and the operation can be simplified on atleast
+     one of the branches once its pushed inside the COND_EXPR.  */
+  if (!TREE_CONSTANT (arg))
+    return NULL_TREE;
 
   if (TREE_CODE (cond) == COND_EXPR)
     {
@@ -4837,28 +4797,11 @@ fold_binary_op_with_conditional_arg (enum tree_code code, tree type,
       false_value = TREE_OPERAND (cond, 2);
       /* If this operand throws an expression, then it does not make
         sense to try to perform a logical or arithmetic operation
-        involving it.  Instead of building `a + throw 3' for example,
-        we simply build `a, throw 3'.  */
+        involving it.  */
       if (VOID_TYPE_P (TREE_TYPE (true_value)))
-       {
-         if (! cond_first_p)
-           {
-             lhs_code = COMPOUND_EXPR;
-             lhs_type = void_type_node;
-           }
-         else
-           lhs = true_value;
-       }
+       lhs = true_value;
       if (VOID_TYPE_P (TREE_TYPE (false_value)))
-       {
-         if (! cond_first_p)
-           {
-             rhs_code = COMPOUND_EXPR;
-             rhs_type = void_type_node;
-           }
-         else
-           rhs = false_value;
-       }
+       rhs = false_value;
     }
   else
     {
@@ -4868,60 +4811,15 @@ fold_binary_op_with_conditional_arg (enum tree_code code, tree type,
       false_value = fold_convert (testtype, integer_zero_node);
     }
 
-  /* If ARG is complex we want to make sure we only evaluate it once.  Though
-     this is only required if it is volatile, it might be more efficient even
-     if it is not.  However, if we succeed in folding one part to a constant,
-     we do not need to make this SAVE_EXPR.  Since we do this optimization
-     primarily to see if we do end up with constant and this SAVE_EXPR
-     interferes with later optimizations, suppressing it when we can is
-     important.
-
-     If we are not in a function, we can't make a SAVE_EXPR, so don't try to
-     do so.  Don't try to see if the result is a constant if an arm is a
-     COND_EXPR since we get exponential behavior in that case.  */
-
-  if (saved_expr_p (arg))
-    save = 1;
-  else if (lhs == 0 && rhs == 0
-          && !TREE_CONSTANT (arg)
-          && (*lang_hooks.decls.global_bindings_p) () == 0
-          && ((TREE_CODE (arg) != VAR_DECL && TREE_CODE (arg) != PARM_DECL)
-              || TREE_SIDE_EFFECTS (arg)))
-    {
-      if (TREE_CODE (true_value) != COND_EXPR)
-       lhs = fold (build (lhs_code, lhs_type, *true_lhs, *true_rhs));
-
-      if (TREE_CODE (false_value) != COND_EXPR)
-       rhs = fold (build (rhs_code, rhs_type, *false_lhs, *false_rhs));
-
-      if ((lhs == 0 || ! TREE_CONSTANT (lhs))
-         && (rhs == 0 || !TREE_CONSTANT (rhs)))
-       {
-         arg = save_expr (arg);
-         lhs = rhs = 0;
-         save = saved_expr_p (arg);
-       }
-    }
-
   if (lhs == 0)
-    lhs = fold (build (lhs_code, lhs_type, *true_lhs, *true_rhs));
+    lhs = fold (cond_first_p ? build2 (code, type, true_value, arg)
+                            : build2 (code, type, arg, true_value));
   if (rhs == 0)
-    rhs = fold (build (rhs_code, rhs_type, *false_lhs, *false_rhs));
-
-  test = fold (build (COND_EXPR, type, test, lhs, rhs));
-
-  /* If ARG involves a SAVE_EXPR, we need to ensure it is evaluated
-     ahead of the COND_EXPR we made.  Otherwise we would have it only
-     evaluated in one branch, with the other branch using the result
-     but missing the evaluation code.  Beware that the save_expr call
-     above might not return a SAVE_EXPR, so testing the TREE_CODE
-     of ARG is not enough to decide here. Â */
-  if (save)
-    return build (COMPOUND_EXPR, type,
-                 fold_convert (void_type_node, arg),
-                 strip_compound_expr (test, arg));
-  else
-    return fold_convert (type, test);
+    rhs = fold (cond_first_p ? build2 (code, type, false_value, arg)
+                            : build2 (code, type, arg, false_value));
+
+  test = fold (build3 (COND_EXPR, type, test, lhs, rhs));
+  return fold_convert (type, test);
 }
 
 \f
@@ -4980,9 +4878,7 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
 {
   REAL_VALUE_TYPE c;
 
-  if (fcode == BUILT_IN_SQRT
-      || fcode == BUILT_IN_SQRTF
-      || fcode == BUILT_IN_SQRTL)
+  if (BUILTIN_SQRT_P (fcode))
     {
       tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
       enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
@@ -5004,8 +4900,8 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
                                     arg);
 
          /* sqrt(x) > y is the same as x >= 0, if y is negative.  */
-         return fold (build (GE_EXPR, type, arg,
-                             build_real (TREE_TYPE (arg), dconst0)));
+         return fold (build2 (GE_EXPR, type, arg,
+                              build_real (TREE_TYPE (arg), dconst0)));
        }
       else if (code == GT_EXPR || code == GE_EXPR)
        {
@@ -5018,8 +4914,8 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
            {
              /* sqrt(x) > y is x == +Inf, when y is very large.  */
              if (HONOR_INFINITIES (mode))
-               return fold (build (EQ_EXPR, type, arg,
-                                   build_real (TREE_TYPE (arg), c2)));
+               return fold (build2 (EQ_EXPR, type, arg,
+                                    build_real (TREE_TYPE (arg), c2)));
 
              /* sqrt(x) > y is always false, when y is very large
                 and we don't care about infinities.  */
@@ -5029,8 +4925,8 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
            }
 
          /* sqrt(x) > c is the same as x > c*c.  */
-         return fold (build (code, type, arg,
-                             build_real (TREE_TYPE (arg), c2)));
+         return fold (build2 (code, type, arg,
+                              build_real (TREE_TYPE (arg), c2)));
        }
       else if (code == LT_EXPR || code == LE_EXPR)
        {
@@ -5051,47 +4947,47 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
              /* sqrt(x) < y is x != +Inf when y is very large and we
                 don't care about NaNs.  */
              if (! HONOR_NANS (mode))
-               return fold (build (NE_EXPR, type, arg,
-                                   build_real (TREE_TYPE (arg), c2)));
+               return fold (build2 (NE_EXPR, type, arg,
+                                    build_real (TREE_TYPE (arg), c2)));
 
              /* sqrt(x) < y is x >= 0 when y is very large and we
                 don't care about Infinities.  */
              if (! HONOR_INFINITIES (mode))
-               return fold (build (GE_EXPR, type, arg,
-                                   build_real (TREE_TYPE (arg), dconst0)));
+               return fold (build2 (GE_EXPR, type, arg,
+                                    build_real (TREE_TYPE (arg), dconst0)));
 
              /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large.  */
-             if ((*lang_hooks.decls.global_bindings_p) () != 0
+             if (lang_hooks.decls.global_bindings_p () != 0
                  || CONTAINS_PLACEHOLDER_P (arg))
                return NULL_TREE;
 
              arg = save_expr (arg);
-             return fold (build (TRUTH_ANDIF_EXPR, type,
-                                 fold (build (GE_EXPR, type, arg,
-                                              build_real (TREE_TYPE (arg),
-                                                          dconst0))),
-                                 fold (build (NE_EXPR, type, arg,
-                                              build_real (TREE_TYPE (arg),
-                                                          c2)))));
+             return fold (build2 (TRUTH_ANDIF_EXPR, type,
+                                  fold (build2 (GE_EXPR, type, arg,
+                                                build_real (TREE_TYPE (arg),
+                                                            dconst0))),
+                                  fold (build2 (NE_EXPR, type, arg,
+                                                build_real (TREE_TYPE (arg),
+                                                            c2)))));
            }
 
          /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs.  */
          if (! HONOR_NANS (mode))
-           return fold (build (code, type, arg,
-                               build_real (TREE_TYPE (arg), c2)));
+           return fold (build2 (code, type, arg,
+                                build_real (TREE_TYPE (arg), c2)));
 
          /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
-         if ((*lang_hooks.decls.global_bindings_p) () == 0
+         if (lang_hooks.decls.global_bindings_p () == 0
              && ! CONTAINS_PLACEHOLDER_P (arg))
            {
              arg = save_expr (arg);
-             return fold (build (TRUTH_ANDIF_EXPR, type,
-                                 fold (build (GE_EXPR, type, arg,
-                                              build_real (TREE_TYPE (arg),
-                                                          dconst0))),
-                                 fold (build (code, type, arg,
-                                              build_real (TREE_TYPE (arg),
-                                                          c2)))));
+             return fold (build2 (TRUTH_ANDIF_EXPR, type,
+                                  fold (build2 (GE_EXPR, type, arg,
+                                                build_real (TREE_TYPE (arg),
+                                                            dconst0))),
+                                  fold (build2 (code, type, arg,
+                                                build_real (TREE_TYPE (arg),
+                                                            c2)))));
            }
        }
     }
@@ -5142,11 +5038,11 @@ fold_inf_compare (enum tree_code code, tree type, tree arg0, tree arg1)
                                 arg0);
 
       /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
-      if ((*lang_hooks.decls.global_bindings_p) () == 0
+      if (lang_hooks.decls.global_bindings_p () == 0
          && ! CONTAINS_PLACEHOLDER_P (arg0))
        {
          arg0 = save_expr (arg0);
-         return fold (build (EQ_EXPR, type, arg0, arg0));
+         return fold (build2 (EQ_EXPR, type, arg0, arg0));
        }
       break;
 
@@ -5154,23 +5050,23 @@ fold_inf_compare (enum tree_code code, tree type, tree arg0, tree arg1)
     case GE_EXPR:
       /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX.  */
       real_maxval (&max, neg, mode);
-      return fold (build (neg ? LT_EXPR : GT_EXPR, type,
-                         arg0, build_real (TREE_TYPE (arg0), max)));
+      return fold (build2 (neg ? LT_EXPR : GT_EXPR, type,
+                          arg0, build_real (TREE_TYPE (arg0), max)));
 
     case LT_EXPR:
       /* x < +Inf is always equal to x <= DBL_MAX.  */
       real_maxval (&max, neg, mode);
-      return fold (build (neg ? GE_EXPR : LE_EXPR, type,
-                         arg0, build_real (TREE_TYPE (arg0), max)));
+      return fold (build2 (neg ? GE_EXPR : LE_EXPR, type,
+                          arg0, build_real (TREE_TYPE (arg0), max)));
 
     case NE_EXPR:
       /* x != +Inf is always equal to !(x > DBL_MAX).  */
       real_maxval (&max, neg, mode);
       if (! HONOR_NANS (mode))
-       return fold (build (neg ? GE_EXPR : LE_EXPR, type,
-                           arg0, build_real (TREE_TYPE (arg0), max)));
-      temp = fold (build (neg ? LT_EXPR : GT_EXPR, type,
-                         arg0, build_real (TREE_TYPE (arg0), max)));
+       return fold (build2 (neg ? GE_EXPR : LE_EXPR, type,
+                            arg0, build_real (TREE_TYPE (arg0), max)));
+      temp = fold (build2 (neg ? LT_EXPR : GT_EXPR, type,
+                          arg0, build_real (TREE_TYPE (arg0), max)));
       return fold (build1 (TRUTH_NOT_EXPR, type, temp));
 
     default:
@@ -5180,6 +5076,156 @@ fold_inf_compare (enum tree_code code, tree type, tree arg0, tree arg1)
   return NULL_TREE;
 }
 
+/* Subroutine of fold() that optimizes comparisons of a division by
+   a non-zero integer constant against an integer constant, i.e.
+   X/C1 op C2.
+
+   CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR,
+   GE_EXPR or LE_EXPR.  TYPE is the type of the result and ARG0 and ARG1
+   are the operands of the comparison.  ARG1 must be a TREE_REAL_CST.
+
+   The function returns the constant folded tree if a simplification
+   can be made, and NULL_TREE otherwise.  */
+
+static tree
+fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
+{
+  tree prod, tmp, hi, lo;
+  tree arg00 = TREE_OPERAND (arg0, 0);
+  tree arg01 = TREE_OPERAND (arg0, 1);
+  unsigned HOST_WIDE_INT lpart;
+  HOST_WIDE_INT hpart;
+  int overflow;
+
+  /* We have to do this the hard way to detect unsigned overflow.
+     prod = int_const_binop (MULT_EXPR, arg01, arg1, 0);  */
+  overflow = mul_double (TREE_INT_CST_LOW (arg01),
+                        TREE_INT_CST_HIGH (arg01),
+                        TREE_INT_CST_LOW (arg1),
+                        TREE_INT_CST_HIGH (arg1), &lpart, &hpart);
+  prod = build_int_2 (lpart, hpart);
+  TREE_TYPE (prod) = TREE_TYPE (arg00);
+  TREE_OVERFLOW (prod) = force_fit_type (prod, overflow)
+                        || TREE_INT_CST_HIGH (prod) != hpart
+                        || TREE_INT_CST_LOW (prod) != lpart;
+  TREE_CONSTANT_OVERFLOW (prod) = TREE_OVERFLOW (prod);
+
+  if (TYPE_UNSIGNED (TREE_TYPE (arg0)))
+    {
+      tmp = int_const_binop (MINUS_EXPR, arg01, integer_one_node, 0);
+      lo = prod;
+
+      /* Likewise hi = int_const_binop (PLUS_EXPR, prod, tmp, 0).  */
+      overflow = add_double (TREE_INT_CST_LOW (prod),
+                            TREE_INT_CST_HIGH (prod),
+                            TREE_INT_CST_LOW (tmp),
+                            TREE_INT_CST_HIGH (tmp),
+                            &lpart, &hpart);
+      hi = build_int_2 (lpart, hpart);
+      TREE_TYPE (hi) = TREE_TYPE (arg00);
+      TREE_OVERFLOW (hi) = force_fit_type (hi, overflow)
+                          || TREE_INT_CST_HIGH (hi) != hpart
+                          || TREE_INT_CST_LOW (hi) != lpart
+                          || TREE_OVERFLOW (prod);
+      TREE_CONSTANT_OVERFLOW (hi) = TREE_OVERFLOW (hi);
+    }
+  else if (tree_int_cst_sgn (arg01) >= 0)
+    {
+      tmp = int_const_binop (MINUS_EXPR, arg01, integer_one_node, 0);
+      switch (tree_int_cst_sgn (arg1))
+       {
+       case -1:
+         lo = int_const_binop (MINUS_EXPR, prod, tmp, 0);
+         hi = prod;
+         break;
+
+       case  0:
+         lo = fold_negate_const (tmp, TREE_TYPE (arg0));
+         hi = tmp;
+         break;
+
+       case  1:
+          hi = int_const_binop (PLUS_EXPR, prod, tmp, 0);
+         lo = prod;
+         break;
+
+       default:
+         abort ();
+       }
+    }
+  else
+    {
+      tmp = int_const_binop (PLUS_EXPR, arg01, integer_one_node, 0);
+      switch (tree_int_cst_sgn (arg1))
+       {
+       case -1:
+         hi = int_const_binop (MINUS_EXPR, prod, tmp, 0);
+         lo = prod;
+         break;
+
+       case  0:
+         hi = fold_negate_const (tmp, TREE_TYPE (arg0));
+         lo = tmp;
+         break;
+
+       case  1:
+          lo = int_const_binop (PLUS_EXPR, prod, tmp, 0);
+         hi = prod;
+         break;
+
+       default:
+         abort ();
+       }
+    }
+
+  switch (code)
+    {
+    case EQ_EXPR:
+      if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi))
+       return omit_one_operand (type, integer_zero_node, arg00);
+      if (TREE_OVERFLOW (hi))
+       return fold (build2 (GE_EXPR, type, arg00, lo));
+      if (TREE_OVERFLOW (lo))
+       return fold (build2 (LE_EXPR, type, arg00, hi));
+      return build_range_check (type, arg00, 1, lo, hi);
+
+    case NE_EXPR:
+      if (TREE_OVERFLOW (lo) && TREE_OVERFLOW (hi))
+       return omit_one_operand (type, integer_one_node, arg00);
+      if (TREE_OVERFLOW (hi))
+       return fold (build2 (LT_EXPR, type, arg00, lo));
+      if (TREE_OVERFLOW (lo))
+       return fold (build2 (GT_EXPR, type, arg00, hi));
+      return build_range_check (type, arg00, 0, lo, hi);
+
+    case LT_EXPR:
+      if (TREE_OVERFLOW (lo))
+       return omit_one_operand (type, integer_zero_node, arg00);
+      return fold (build2 (LT_EXPR, type, arg00, lo));
+
+    case LE_EXPR:
+      if (TREE_OVERFLOW (hi))
+       return omit_one_operand (type, integer_one_node, arg00);
+      return fold (build2 (LE_EXPR, type, arg00, hi));
+
+    case GT_EXPR:
+      if (TREE_OVERFLOW (hi))
+       return omit_one_operand (type, integer_zero_node, arg00);
+      return fold (build2 (GT_EXPR, type, arg00, hi));
+
+    case GE_EXPR:
+      if (TREE_OVERFLOW (lo))
+       return omit_one_operand (type, integer_one_node, arg00);
+      return fold (build2 (GE_EXPR, type, arg00, lo));
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+
 /* If CODE with arguments ARG0 and ARG1 represents a single bit
    equality/inequality test, then return a simplified form of
    the test using shifts and logical operations.  Otherwise return
@@ -5223,10 +5269,10 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
       arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
       if (arg00 != NULL_TREE)
        {
-         tree stype = (*lang_hooks.types.signed_type) (TREE_TYPE (arg00));
-         return fold (build (code == EQ_EXPR ? GE_EXPR : LT_EXPR, result_type,
-                             fold_convert (stype, arg00),
-                             fold_convert (stype, integer_zero_node)));
+         tree stype = lang_hooks.types.signed_type (TREE_TYPE (arg00));
+         return fold (build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
+                              result_type, fold_convert (stype, arg00),
+                              fold_convert (stype, integer_zero_node)));
        }
 
       /* At this point, we know that arg0 is not testing the sign bit.  */
@@ -5259,22 +5305,22 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
       ops_unsigned = 1;
 #endif
 
-      signed_type = (*lang_hooks.types.type_for_mode) (operand_mode, 0);
-      unsigned_type = (*lang_hooks.types.type_for_mode) (operand_mode, 1);
+      signed_type = lang_hooks.types.type_for_mode (operand_mode, 0);
+      unsigned_type = lang_hooks.types.type_for_mode (operand_mode, 1);
       intermediate_type = ops_unsigned ? unsigned_type : signed_type;
       inner = fold_convert (intermediate_type, inner);
 
       if (bitnum != 0)
-       inner = build (RSHIFT_EXPR, intermediate_type,
-                      inner, size_int (bitnum));
+       inner = build2 (RSHIFT_EXPR, intermediate_type,
+                       inner, size_int (bitnum));
 
       if (code == EQ_EXPR)
-       inner = build (BIT_XOR_EXPR, intermediate_type,
-                      inner, integer_one_node);
+       inner = build2 (BIT_XOR_EXPR, intermediate_type,
+                       inner, integer_one_node);
 
       /* Put the AND last so it can combine with more things.  */
-      inner = build (BIT_AND_EXPR, intermediate_type,
-                    inner, integer_one_node);
+      inner = build2 (BIT_AND_EXPR, intermediate_type,
+                     inner, integer_one_node);
 
       /* Make sure to return the proper type.  */
       inner = fold_convert (result_type, inner);
@@ -5341,6 +5387,15 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
   if (DECL_P (arg0))
     return 1;
 
+  if (reorder && flag_evaluation_order
+      && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)))
+    return 0;
+
+  if (DECL_P (arg1))
+    return 0;
+  if (DECL_P (arg0))
+    return 1;
+
   return 0;
 }
 
@@ -5348,7 +5403,7 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
    The related simplifications include x*1 => x, x*0 => 0, etc.,
    and application of the associative law.
    NOP_EXPR conversions may be removed freely (as long as we
-   are careful not to change the C type of the overall expression)
+   are careful not to change the type of the overall expression).
    We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR,
    but we can constant-fold them if they have constant operands.  */
 
@@ -5360,14 +5415,14 @@ static
 tree
 fold (tree expr)
 {
-  tree t = expr, orig_t;
+  const tree t = expr;
+  const tree type = TREE_TYPE (expr);
   tree t1 = NULL_TREE;
   tree tem;
-  tree type = TREE_TYPE (expr);
   tree arg0 = NULL_TREE, arg1 = NULL_TREE;
   enum tree_code code = TREE_CODE (t);
   int kind = TREE_CODE_CLASS (code);
-  int invert;
+
   /* WINS will be nonzero when the switch is done
      if all operands are constant.  */
   int wins = 1;
@@ -5381,8 +5436,6 @@ fold (tree expr)
   if (kind == 'c')
     return t;
 
-  orig_t = t;
-
   if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
     {
       tree subop;
@@ -5418,14 +5471,20 @@ fold (tree expr)
          if (op == 0)
            continue;           /* Valid for CALL_EXPR, at least.  */
 
-         if (kind == '<' || code == RSHIFT_EXPR)
-           {
-             /* Signedness matters here.  Perhaps we can refine this
-                later.  */
-             STRIP_SIGN_NOPS (op);
-           }
+         /* Strip any conversions that don't change the mode.  This is
+            safe for every expression, except for a comparison expression
+            because its signedness is derived from its operands.  So, in
+            the latter case, only strip conversions that don't change the
+            signedness.
+
+            Note that this is done as an internal manipulation within the
+            constant folder, in order to find the simplest representation
+            of the arguments so that their form can be studied.  In any
+            cases, the appropriate type conversions should be put back in
+            the tree that will get out of the constant folder.  */
+         if (kind == '<')
+           STRIP_SIGN_NOPS (op);
          else
-           /* Strip any conversions that don't change the mode.  */
            STRIP_NOPS (op);
 
          if (TREE_CODE (op) == COMPLEX_CST)
@@ -5451,7 +5510,8 @@ fold (tree expr)
      to ARG1 to reduce the number of tests below.  */
   if (commutative_tree_code (code)
       && tree_swap_operands_p (arg0, arg1, true))
-    return fold (build (code, type, arg1, arg0));
+    return fold (build2 (code, type, TREE_OPERAND (t, 1),
+                        TREE_OPERAND (t, 0)));
 
   /* Now WINS is set as described above,
      ARG0 is the first operand of EXPR,
@@ -5482,22 +5542,23 @@ fold (tree expr)
                  || (TREE_CODE (arg0) == BIT_AND_EXPR
                      && integer_onep (TREE_OPERAND (arg0, 1)))))))
     {
-      t = fold (build (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
-                      : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
-                      : TRUTH_XOR_EXPR,
-                      type, arg0, arg1));
+      tem = fold (build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
+                         : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
+                         : TRUTH_XOR_EXPR,
+                         type, fold_convert (boolean_type_node, arg0),
+                         fold_convert (boolean_type_node, arg1)));
 
       if (code == EQ_EXPR)
-       t = invert_truthvalue (t);
+       tem = invert_truthvalue (tem);
 
-      return t;
+      return tem;
     }
 
   if (TREE_CODE_CLASS (code) == '1')
     {
       if (TREE_CODE (arg0) == COMPOUND_EXPR)
-       return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                     fold (build1 (code, type, TREE_OPERAND (arg0, 1))));
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                      fold (build1 (code, type, TREE_OPERAND (arg0, 1))));
       else if (TREE_CODE (arg0) == COND_EXPR)
        {
          tree arg01 = TREE_OPERAND (arg0, 1);
@@ -5506,8 +5567,8 @@ fold (tree expr)
            arg01 = fold (build1 (code, type, arg01));
          if (! VOID_TYPE_P (TREE_TYPE (arg02)))
            arg02 = fold (build1 (code, type, arg02));
-         t = fold (build (COND_EXPR, type, TREE_OPERAND (arg0, 0),
-                          arg01, arg02));
+         tem = fold (build3 (COND_EXPR, type, TREE_OPERAND (arg0, 0),
+                             arg01, arg02));
 
          /* If this was a conversion, and all we did was to move into
             inside the COND_EXPR, bring it back out.  But leave it if
@@ -5520,85 +5581,84 @@ fold (tree expr)
 
          if ((code == NOP_EXPR || code == CONVERT_EXPR
               || code == NON_LVALUE_EXPR)
-             && TREE_CODE (t) == COND_EXPR
-             && TREE_CODE (TREE_OPERAND (t, 1)) == code
-             && TREE_CODE (TREE_OPERAND (t, 2)) == code
-             && ! VOID_TYPE_P (TREE_OPERAND (t, 1))
-             && ! VOID_TYPE_P (TREE_OPERAND (t, 2))
-             && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0))
-                 == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 2), 0)))
-             && ! (INTEGRAL_TYPE_P (TREE_TYPE (t))
+             && TREE_CODE (tem) == COND_EXPR
+             && TREE_CODE (TREE_OPERAND (tem, 1)) == code
+             && TREE_CODE (TREE_OPERAND (tem, 2)) == code
+             && ! VOID_TYPE_P (TREE_OPERAND (tem, 1))
+             && ! VOID_TYPE_P (TREE_OPERAND (tem, 2))
+             && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))
+                 == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0)))
+             && ! (INTEGRAL_TYPE_P (TREE_TYPE (tem))
                    && (INTEGRAL_TYPE_P
-                       (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0))))
-                   && TYPE_PRECISION (TREE_TYPE (t)) <= BITS_PER_WORD))
-           t = build1 (code, type,
-                       build (COND_EXPR,
-                              TREE_TYPE (TREE_OPERAND
-                                         (TREE_OPERAND (t, 1), 0)),
-                              TREE_OPERAND (t, 0),
-                              TREE_OPERAND (TREE_OPERAND (t, 1), 0),
-                              TREE_OPERAND (TREE_OPERAND (t, 2), 0)));
-         return t;
+                       (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))))
+                   && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD))
+           tem = build1 (code, type,
+                         build3 (COND_EXPR,
+                                 TREE_TYPE (TREE_OPERAND
+                                            (TREE_OPERAND (tem, 1), 0)),
+                                 TREE_OPERAND (tem, 0),
+                                 TREE_OPERAND (TREE_OPERAND (tem, 1), 0),
+                                 TREE_OPERAND (TREE_OPERAND (tem, 2), 0)));
+         return tem;
        }
       else if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
-       return fold (build (COND_EXPR, type, arg0,
-                           fold (build1 (code, type, integer_one_node)),
-                           fold (build1 (code, type, integer_zero_node))));
+       {
+         if (TREE_CODE (type) == BOOLEAN_TYPE)
+           {
+             arg0 = copy_node (arg0);
+             TREE_TYPE (arg0) = type;
+             return arg0;
+           }
+         else if (TREE_CODE (type) != INTEGER_TYPE)
+           return fold (build3 (COND_EXPR, type, arg0,
+                                fold (build1 (code, type,
+                                              integer_one_node)),
+                                fold (build1 (code, type,
+                                              integer_zero_node))));
+       }
    }
   else if (TREE_CODE_CLASS (code) == '<'
           && TREE_CODE (arg0) == COMPOUND_EXPR)
-    return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                 fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
+    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                  fold (build2 (code, type, TREE_OPERAND (arg0, 1), arg1)));
   else if (TREE_CODE_CLASS (code) == '<'
           && TREE_CODE (arg1) == COMPOUND_EXPR)
-    return build (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
-                 fold (build (code, type, arg0, TREE_OPERAND (arg1, 1))));
+    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+                  fold (build2 (code, type, arg0, TREE_OPERAND (arg1, 1))));
   else if (TREE_CODE_CLASS (code) == '2'
           || TREE_CODE_CLASS (code) == '<')
     {
+      if (TREE_CODE (arg0) == COMPOUND_EXPR)
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                      fold (build2 (code, type, TREE_OPERAND (arg0, 1),
+                                    arg1)));
       if (TREE_CODE (arg1) == COMPOUND_EXPR
-         && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg1, 0))
-         && ! TREE_SIDE_EFFECTS (arg0))
-       return build (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
-                     fold (build (code, type,
-                                  arg0, TREE_OPERAND (arg1, 1))));
-      else if ((TREE_CODE (arg1) == COND_EXPR
-               || (TREE_CODE_CLASS (TREE_CODE (arg1)) == '<'
-                   && TREE_CODE_CLASS (code) != '<'))
-              && (TREE_CODE (arg0) != COND_EXPR
-                  || count_cond (arg0, 25) + count_cond (arg1, 25) <= 25)
-              && (! TREE_SIDE_EFFECTS (arg0)
-                  || ((*lang_hooks.decls.global_bindings_p) () == 0
-                      && ! CONTAINS_PLACEHOLDER_P (arg0))))
-       return
-         fold_binary_op_with_conditional_arg (code, type, arg1, arg0,
-                                              /*cond_first_p=*/0);
-      else if (TREE_CODE (arg0) == COMPOUND_EXPR)
-       return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                     fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
-      else if ((TREE_CODE (arg0) == COND_EXPR
-               || (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
-                   && TREE_CODE_CLASS (code) != '<'))
-              && (TREE_CODE (arg1) != COND_EXPR
-                  || count_cond (arg0, 25) + count_cond (arg1, 25) <= 25)
-              && (! TREE_SIDE_EFFECTS (arg1)
-                  || ((*lang_hooks.decls.global_bindings_p) () == 0
-                      && ! CONTAINS_PLACEHOLDER_P (arg1))))
-       return
-         fold_binary_op_with_conditional_arg (code, type, arg0, arg1,
-                                              /*cond_first_p=*/1);
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+                      fold (build2 (code, type,
+                                    arg0, TREE_OPERAND (arg1, 1))));
+
+      if (TREE_CODE (arg0) == COND_EXPR
+         || TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
+       {
+         tem = fold_binary_op_with_conditional_arg (code, type, arg0, arg1,
+                                                    /*cond_first_p=*/1);
+         if (tem != NULL_TREE)
+           return tem;
+       }
+
+      if (TREE_CODE (arg1) == COND_EXPR
+         || TREE_CODE_CLASS (TREE_CODE (arg1)) == '<')
+       {
+         tem = fold_binary_op_with_conditional_arg (code, type, arg1, arg0,
+                                                    /*cond_first_p=*/0);
+         if (tem != NULL_TREE)
+           return tem;
+       }
     }
 
   switch (code)
     {
-    case INTEGER_CST:
-    case REAL_CST:
-    case VECTOR_CST:
-    case STRING_CST:
-    case COMPLEX_CST:
-    case CONSTRUCTOR:
-      return t;
-
     case CONST_DECL:
       return fold (DECL_INITIAL (t));
 
@@ -5608,7 +5668,8 @@ fold (tree expr)
     case FIX_TRUNC_EXPR:
     case FIX_CEIL_EXPR:
     case FIX_FLOOR_EXPR:
-      if (TREE_TYPE (TREE_OPERAND (t, 0)) == TREE_TYPE (t))
+    case FIX_ROUND_EXPR:
+      if (TREE_TYPE (TREE_OPERAND (t, 0)) == type)
        return TREE_OPERAND (t, 0);
 
       /* Handle cases of two conversions in a row.  */
@@ -5617,31 +5678,30 @@ fold (tree expr)
        {
          tree inside_type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
          tree inter_type = TREE_TYPE (TREE_OPERAND (t, 0));
-         tree final_type = TREE_TYPE (t);
          int inside_int = INTEGRAL_TYPE_P (inside_type);
          int inside_ptr = POINTER_TYPE_P (inside_type);
          int inside_float = FLOAT_TYPE_P (inside_type);
          unsigned int inside_prec = TYPE_PRECISION (inside_type);
-         int inside_unsignedp = TREE_UNSIGNED (inside_type);
+         int inside_unsignedp = TYPE_UNSIGNED (inside_type);
          int inter_int = INTEGRAL_TYPE_P (inter_type);
          int inter_ptr = POINTER_TYPE_P (inter_type);
          int inter_float = FLOAT_TYPE_P (inter_type);
          unsigned int inter_prec = TYPE_PRECISION (inter_type);
-         int inter_unsignedp = TREE_UNSIGNED (inter_type);
-         int final_int = INTEGRAL_TYPE_P (final_type);
-         int final_ptr = POINTER_TYPE_P (final_type);
-         int final_float = FLOAT_TYPE_P (final_type);
-         unsigned int final_prec = TYPE_PRECISION (final_type);
-         int final_unsignedp = TREE_UNSIGNED (final_type);
+         int inter_unsignedp = TYPE_UNSIGNED (inter_type);
+         int final_int = INTEGRAL_TYPE_P (type);
+         int final_ptr = POINTER_TYPE_P (type);
+         int final_float = FLOAT_TYPE_P (type);
+         unsigned int final_prec = TYPE_PRECISION (type);
+         int final_unsignedp = TYPE_UNSIGNED (type);
 
          /* In addition to the cases of two conversions in a row
             handled below, if we are converting something to its own
             type via an object of identical or wider precision, neither
             conversion is needed.  */
-         if (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (final_type)
+         if (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (type)
              && ((inter_int && final_int) || (inter_float && final_float))
              && inter_prec >= final_prec)
-           return fold (build1 (code, final_type,
+           return fold (build1 (code, type,
                                 TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
 
          /* Likewise, if the intermediate and final types are either both
@@ -5654,10 +5714,10 @@ fold (tree expr)
               || (inter_float && inside_float))
              && inter_prec >= inside_prec
              && (inter_float || inter_unsignedp == inside_unsignedp)
-             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
-                   && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+                   && TYPE_MODE (type) == TYPE_MODE (inter_type))
              && ! final_ptr)
-           return fold (build1 (code, final_type,
+           return fold (build1 (code, type,
                                 TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
 
          /* If we have a sign-extension of a zero-extended value, we can
@@ -5665,7 +5725,7 @@ fold (tree expr)
          if (inside_int && inter_int && final_int
              && inside_prec < inter_prec && inter_prec < final_prec
              && inside_unsignedp && !inter_unsignedp)
-           return fold (build1 (code, final_type,
+           return fold (build1 (code, type,
                                 TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
 
          /* Two conversions in a row are not needed unless:
@@ -5687,10 +5747,10 @@ fold (tree expr)
                  == (final_unsignedp && final_prec > inter_prec))
              && ! (inside_ptr && inter_prec != final_prec)
              && ! (final_ptr && inside_prec != inter_prec)
-             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
-                   && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+                   && TYPE_MODE (type) == TYPE_MODE (inter_type))
              && ! final_ptr)
-           return fold (build1 (code, final_type,
+           return fold (build1 (code, type,
                                 TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
        }
 
@@ -5703,20 +5763,20 @@ fold (tree expr)
          /* Don't leave an assignment inside a conversion
             unless assigning a bitfield.  */
          tree prev = TREE_OPERAND (t, 0);
-         if (t == orig_t)
-           t = copy_node (t);
-         TREE_OPERAND (t, 0) = TREE_OPERAND (prev, 1);
+         tem = copy_node (t);
+         TREE_OPERAND (tem, 0) = TREE_OPERAND (prev, 1);
          /* First do the assignment, then return converted constant.  */
-         t = build (COMPOUND_EXPR, TREE_TYPE (t), prev, fold (t));
-         TREE_USED (t) = 1;
-         return t;
+         tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), prev, fold (tem));
+         TREE_NO_WARNING (tem) = 1;
+         TREE_USED (tem) = 1;
+         return tem;
        }
 
       /* Convert (T)(x & c) into (T)x & (T)c, if c is an integer
         constants (if x has signed type, the sign bit cannot be set
         in c).  This folds extension into the BIT_AND_EXPR.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (t))
-         && TREE_CODE (TREE_TYPE (t)) != BOOLEAN_TYPE
+      if (INTEGRAL_TYPE_P (type)
+         && TREE_CODE (type) != BOOLEAN_TYPE
          && TREE_CODE (TREE_OPERAND (t, 0)) == BIT_AND_EXPR
          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == INTEGER_CST)
        {
@@ -5724,8 +5784,8 @@ fold (tree expr)
          tree and0 = TREE_OPERAND (and, 0), and1 = TREE_OPERAND (and, 1);
          int change = 0;
 
-         if (TREE_UNSIGNED (TREE_TYPE (and))
-             || (TYPE_PRECISION (TREE_TYPE (t))
+         if (TYPE_UNSIGNED (TREE_TYPE (and))
+             || (TYPE_PRECISION (type)
                  <= TYPE_PRECISION (TREE_TYPE (and))))
            change = 1;
          else if (TYPE_PRECISION (TREE_TYPE (and1))
@@ -5743,19 +5803,39 @@ fold (tree expr)
                  && (LOAD_EXTEND_OP (TYPE_MODE (TREE_TYPE (and0)))
                      == ZERO_EXTEND))
                {
-                 tree uns = (*lang_hooks.types.unsigned_type) (TREE_TYPE (and0));
+                 tree uns = lang_hooks.types.unsigned_type (TREE_TYPE (and0));
                  and0 = fold_convert (uns, and0);
                  and1 = fold_convert (uns, and1);
                }
 #endif
            }
          if (change)
-           return fold (build (BIT_AND_EXPR, TREE_TYPE (t),
-                               fold_convert (TREE_TYPE (t), and0),
-                               fold_convert (TREE_TYPE (t), and1)));
+           return fold (build2 (BIT_AND_EXPR, type,
+                                fold_convert (type, and0),
+                                fold_convert (type, and1)));
+       }
+
+      /* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and
+        T2 being pointers to types of the same size.  */
+      if (POINTER_TYPE_P (TREE_TYPE (t))
+         && TREE_CODE_CLASS (TREE_CODE (arg0)) == '2'
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
+         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+       {
+         tree arg00 = TREE_OPERAND (arg0, 0);
+         tree t0 = TREE_TYPE (t);
+         tree t1 = TREE_TYPE (arg00);
+         tree tt0 = TREE_TYPE (t0);
+         tree tt1 = TREE_TYPE (t1);
+         tree s0 = TYPE_SIZE (tt0);
+         tree s1 = TYPE_SIZE (tt1);
+
+         if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST))
+           return build2 (TREE_CODE (arg0), t0, fold_convert (t0, arg00),
+                          TREE_OPERAND (arg0, 1));
        }
 
-      tem = fold_convert_const (code, TREE_TYPE (t), arg0);
+      tem = fold_convert_const (code, type, arg0);
       return tem ? tem : t;
 
     case VIEW_CONVERT_EXPR:
@@ -5770,16 +5850,17 @@ fold (tree expr)
        {
          tree m = purpose_member (arg1, CONSTRUCTOR_ELTS (arg0));
          if (m)
-           t = TREE_VALUE (m);
+           return TREE_VALUE (m);
        }
       return t;
 
     case RANGE_EXPR:
       if (TREE_CONSTANT (t) != wins)
        {
-         if (t == orig_t)
-           t = copy_node (t);
-         TREE_CONSTANT (t) = wins;
+         tem = copy_node (t);
+         TREE_CONSTANT (tem) = wins;
+         TREE_INVARIANT (tem) = wins;
+         return tem;
        }
       return t;
 
@@ -5789,42 +5870,9 @@ fold (tree expr)
       return t;
 
     case ABS_EXPR:
-      if (wins)
-       {
-         if (TREE_CODE (arg0) == INTEGER_CST)
-           {
-             /* If the value is unsigned, then the absolute value is
-                the same as the ordinary value.  */
-             if (TREE_UNSIGNED (type))
-               return arg0;
-             /* Similarly, if the value is non-negative.  */
-             else if (INT_CST_LT (integer_minus_one_node, arg0))
-               return arg0;
-             /* If the value is negative, then the absolute value is
-                its negation.  */
-             else
-               {
-                 unsigned HOST_WIDE_INT low;
-                 HOST_WIDE_INT high;
-                 int overflow = neg_double (TREE_INT_CST_LOW (arg0),
-                                            TREE_INT_CST_HIGH (arg0),
-                                            &low, &high);
-                 t = build_int_2 (low, high);
-                 TREE_TYPE (t) = type;
-                 TREE_OVERFLOW (t)
-                   = (TREE_OVERFLOW (arg0)
-                      | force_fit_type (t, overflow));
-                 TREE_CONSTANT_OVERFLOW (t)
-                   = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
-               }
-           }
-         else if (TREE_CODE (arg0) == REAL_CST)
-           {
-             if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0)))
-               t = build_real (type,
-                               REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
-           }
-       }
+      if (wins
+         && (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST))
+       return fold_abs_const (arg0, type);
       else if (TREE_CODE (arg0) == NEGATE_EXPR)
        return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0)));
       /* Convert fabs((double)float) into (double)fabsf(float).  */
@@ -5845,18 +5893,18 @@ fold (tree expr)
       if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
        return fold_convert (type, arg0);
       else if (TREE_CODE (arg0) == COMPLEX_EXPR)
-       return build (COMPLEX_EXPR, type,
-                     TREE_OPERAND (arg0, 0),
-                     negate_expr (TREE_OPERAND (arg0, 1)));
+       return build2 (COMPLEX_EXPR, type,
+                      TREE_OPERAND (arg0, 0),
+                      negate_expr (TREE_OPERAND (arg0, 1)));
       else if (TREE_CODE (arg0) == COMPLEX_CST)
        return build_complex (type, TREE_REALPART (arg0),
                              negate_expr (TREE_IMAGPART (arg0)));
       else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-       return fold (build (TREE_CODE (arg0), type,
-                           fold (build1 (CONJ_EXPR, type,
-                                         TREE_OPERAND (arg0, 0))),
-                           fold (build1 (CONJ_EXPR,
-                                         type, TREE_OPERAND (arg0, 1)))));
+       return fold (build2 (TREE_CODE (arg0), type,
+                            fold (build1 (CONJ_EXPR, type,
+                                          TREE_OPERAND (arg0, 0))),
+                            fold (build1 (CONJ_EXPR, type,
+                                          TREE_OPERAND (arg0, 1)))));
       else if (TREE_CODE (arg0) == CONJ_EXPR)
        return TREE_OPERAND (arg0, 0);
       return t;
@@ -5864,12 +5912,13 @@ fold (tree expr)
     case BIT_NOT_EXPR:
       if (wins)
        {
-         t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
-                          ~ TREE_INT_CST_HIGH (arg0));
-         TREE_TYPE (t) = type;
-         force_fit_type (t, 0);
-         TREE_OVERFLOW (t) = TREE_OVERFLOW (arg0);
-         TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (arg0);
+         tem = build_int_2 (~ TREE_INT_CST_LOW (arg0),
+                            ~ TREE_INT_CST_HIGH (arg0));
+         TREE_TYPE (tem) = type;
+         force_fit_type (tem, 0);
+         TREE_OVERFLOW (tem) = TREE_OVERFLOW (arg0);
+         TREE_CONSTANT_OVERFLOW (tem) = TREE_CONSTANT_OVERFLOW (arg0);
+         return tem;
        }
       else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
        return TREE_OPERAND (arg0, 0);
@@ -5878,11 +5927,12 @@ fold (tree expr)
     case PLUS_EXPR:
       /* A + (-B) -> A - B */
       if (TREE_CODE (arg1) == NEGATE_EXPR)
-       return fold (build (MINUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
+       return fold (build2 (MINUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
       /* (-A) + B -> B - A */
-      if (TREE_CODE (arg0) == NEGATE_EXPR)
-       return fold (build (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
-      else if (! FLOAT_TYPE_P (type))
+      if (TREE_CODE (arg0) == NEGATE_EXPR
+         && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
+       return fold (build2 (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
+      if (! FLOAT_TYPE_P (type))
        {
          if (integer_zerop (arg1))
            return non_lvalue (fold_convert (type, arg0));
@@ -5924,18 +5974,18 @@ fold (tree expr)
 
              if (TREE_CODE (parg0) == MULT_EXPR
                  && TREE_CODE (parg1) != MULT_EXPR)
-               return fold (build (PLUS_EXPR, type,
-                                   fold (build (PLUS_EXPR, type,
-                                                fold_convert (type, parg0),
-                                                fold_convert (type, marg))),
-                                   fold_convert (type, parg1)));
+               return fold (build2 (PLUS_EXPR, type,
+                                    fold (build2 (PLUS_EXPR, type,
+                                                  fold_convert (type, parg0),
+                                                  fold_convert (type, marg))),
+                                    fold_convert (type, parg1)));
              if (TREE_CODE (parg0) != MULT_EXPR
                  && TREE_CODE (parg1) == MULT_EXPR)
-               return fold (build (PLUS_EXPR, type,
-                                   fold (build (PLUS_EXPR, type,
-                                                fold_convert (type, parg1),
-                                                fold_convert (type, marg))),
-                                   fold_convert (type, parg0)));
+               return fold (build2 (PLUS_EXPR, type,
+                                    fold (build2 (PLUS_EXPR, type,
+                                                  fold_convert (type, parg1),
+                                                  fold_convert (type, marg))),
+                                    fold_convert (type, parg0)));
            }
 
          if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
@@ -5986,17 +6036,18 @@ fold (tree expr)
 
                  if (exact_log2 (int11) > 0 && int01 % int11 == 0)
                    {
-                     alt0 = fold (build (MULT_EXPR, type, arg00,
-                                         build_int_2 (int01 / int11, 0)));
+                     alt0 = fold (build2 (MULT_EXPR, type, arg00,
+                                          build_int_2 (int01 / int11, 0)));
                      alt1 = arg10;
                      same = arg11;
                    }
                }
 
              if (same)
-               return fold (build (MULT_EXPR, type,
-                                   fold (build (PLUS_EXPR, type, alt0, alt1)),
-                                   same));
+               return fold (build2 (MULT_EXPR, type,
+                                    fold (build2 (PLUS_EXPR, type,
+                                                  alt0, alt1)),
+                                    same));
            }
        }
       else
@@ -6012,8 +6063,8 @@ fold (tree expr)
          /* Convert x+x into x*2.0.  */
          if (operand_equal_p (arg0, arg1, 0)
              && SCALAR_FLOAT_TYPE_P (type))
-           return fold (build (MULT_EXPR, type, arg0,
-                               build_real (type, dconst2)));
+           return fold (build2 (MULT_EXPR, type, arg0,
+                                build_real (type, dconst2)));
 
          /* Convert x*c+x into x*(c+1).  */
          if (flag_unsafe_math_optimizations
@@ -6026,8 +6077,8 @@ fold (tree expr)
 
              c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
              real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold (build (MULT_EXPR, type, arg1,
-                                 build_real (type, c)));
+             return fold (build2 (MULT_EXPR, type, arg1,
+                                  build_real (type, c)));
            }
 
          /* Convert x+x*c into x*(c+1).  */
@@ -6041,8 +6092,8 @@ fold (tree expr)
 
              c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
              real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold (build (MULT_EXPR, type, arg0,
-                                 build_real (type, c)));
+             return fold (build2 (MULT_EXPR, type, arg0,
+                                  build_real (type, c)));
            }
 
          /* Convert x*c1+x*c2 into x*(c1+c2).  */
@@ -6061,10 +6112,40 @@ fold (tree expr)
              c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
              c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
              real_arithmetic (&c1, PLUS_EXPR, &c1, &c2);
-             return fold (build (MULT_EXPR, type,
-                                 TREE_OPERAND (arg0, 0),
-                                 build_real (type, c1)));
+             return fold (build2 (MULT_EXPR, type,
+                                  TREE_OPERAND (arg0, 0),
+                                  build_real (type, c1)));
            }
+          /* Convert a + (b*c + d*e) into (a + b*c) + d*e */
+          if (flag_unsafe_math_optimizations
+              && TREE_CODE (arg1) == PLUS_EXPR
+              && TREE_CODE (arg0) != MULT_EXPR)
+            {
+              tree tree10 = TREE_OPERAND (arg1, 0);
+              tree tree11 = TREE_OPERAND (arg1, 1);
+              if (TREE_CODE (tree11) == MULT_EXPR
+                 && TREE_CODE (tree10) == MULT_EXPR)
+                {
+                  tree tree0;
+                  tree0 = fold (build2 (PLUS_EXPR, type, arg0, tree10));
+                  return fold (build2 (PLUS_EXPR, type, tree0, tree11));
+                }
+            }
+          /* Convert (b*c + d*e) + a into b*c + (d*e +a) */
+          if (flag_unsafe_math_optimizations
+              && TREE_CODE (arg0) == PLUS_EXPR
+              && TREE_CODE (arg1) != MULT_EXPR)
+            {
+              tree tree00 = TREE_OPERAND (arg0, 0);
+              tree tree01 = TREE_OPERAND (arg0, 1);
+              if (TREE_CODE (tree01) == MULT_EXPR
+                 && TREE_CODE (tree00) == MULT_EXPR)
+                {
+                  tree tree0;
+                  tree0 = fold (build2 (PLUS_EXPR, type, tree01, arg1));
+                  return fold (build2 (PLUS_EXPR, type, tree00, tree0));
+                }
+            }
        }
 
      bit_rotate:
@@ -6080,7 +6161,7 @@ fold (tree expr)
             || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
            && operand_equal_p (TREE_OPERAND (arg0, 0),
                                TREE_OPERAND (arg1, 0), 0)
-           && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+           && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
          {
            tree tree01, tree11;
            enum tree_code code01, code11;
@@ -6097,8 +6178,8 @@ fold (tree expr)
                && TREE_INT_CST_HIGH (tree11) == 0
                && ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
                    == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
-             return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
-                           code0 == LSHIFT_EXPR ? tree01 : tree11);
+             return build2 (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
+                            code0 == LSHIFT_EXPR ? tree01 : tree11);
            else if (code11 == MINUS_EXPR)
              {
                tree tree110, tree111;
@@ -6112,10 +6193,10 @@ fold (tree expr)
                                              (TREE_TYPE (TREE_OPERAND
                                                          (arg0, 0))))
                    && operand_equal_p (tree01, tree111, 0))
-                 return build ((code0 == LSHIFT_EXPR
-                                ? LROTATE_EXPR
-                                : RROTATE_EXPR),
-                               type, TREE_OPERAND (arg0, 0), tree01);
+                 return build2 ((code0 == LSHIFT_EXPR
+                                 ? LROTATE_EXPR
+                                 : RROTATE_EXPR),
+                                type, TREE_OPERAND (arg0, 0), tree01);
              }
            else if (code01 == MINUS_EXPR)
              {
@@ -6130,10 +6211,10 @@ fold (tree expr)
                                              (TREE_TYPE (TREE_OPERAND
                                                          (arg0, 0))))
                    && operand_equal_p (tree11, tree011, 0))
-                 return build ((code0 != LSHIFT_EXPR
-                                ? LROTATE_EXPR
-                                : RROTATE_EXPR),
-                               type, TREE_OPERAND (arg0, 0), tree11);
+                 return build2 ((code0 != LSHIFT_EXPR
+                                 ? LROTATE_EXPR
+                                 : RROTATE_EXPR),
+                                type, TREE_OPERAND (arg0, 0), tree11);
              }
          }
       }
@@ -6226,8 +6307,8 @@ fold (tree expr)
        {
          /* The return value should always have
             the same type as the original expression.  */
-         if (TREE_TYPE (t1) != TREE_TYPE (t))
-           t1 = fold_convert (TREE_TYPE (t), t1);
+         if (TREE_TYPE (t1) != type)
+           t1 = fold_convert (type, t1);
 
          return t1;
        }
@@ -6236,15 +6317,15 @@ fold (tree expr)
     case MINUS_EXPR:
       /* A - (-B) -> A + B */
       if (TREE_CODE (arg1) == NEGATE_EXPR)
-       return fold (build (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
+       return fold (build2 (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
       /* (-A) - B -> (-B) - A  where B is easily negated and we can swap.  */
       if (TREE_CODE (arg0) == NEGATE_EXPR
          && (FLOAT_TYPE_P (type)
              || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))
          && negate_expr_p (arg1)
          && reorder_operands_p (arg0, arg1))
-       return fold (build (MINUS_EXPR, type, negate_expr (arg1),
-                           TREE_OPERAND (arg0, 0)));
+       return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
+                            TREE_OPERAND (arg0, 0)));
 
       if (! FLOAT_TYPE_P (type))
        {
@@ -6258,15 +6339,15 @@ fold (tree expr)
              && TREE_CODE (arg1) == BIT_AND_EXPR)
            {
              if (operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0))
-               return fold (build (BIT_AND_EXPR, type,
-                                   fold (build1 (BIT_NOT_EXPR, type,
-                                                 TREE_OPERAND (arg1, 0))),
-                                   arg0));
+               return fold (build2 (BIT_AND_EXPR, type,
+                                    fold (build1 (BIT_NOT_EXPR, type,
+                                                  TREE_OPERAND (arg1, 0))),
+                                    arg0));
              if (operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
-               return fold (build (BIT_AND_EXPR, type,
-                                   fold (build1 (BIT_NOT_EXPR, type,
-                                                 TREE_OPERAND (arg1, 1))),
-                                   arg0));
+               return fold (build2 (BIT_AND_EXPR, type,
+                                    fold (build1 (BIT_NOT_EXPR, type,
+                                                  TREE_OPERAND (arg1, 1))),
+                                    arg0));
            }
 
          /* Fold (A & ~B) - (A & B) into (A ^ B) - B, where B is
@@ -6282,9 +6363,9 @@ fold (tree expr)
              
              if (operand_equal_p (tem, mask1, 0))
                {
-                 tem = fold (build (BIT_XOR_EXPR, type,
-                                    TREE_OPERAND (arg0, 0), mask1));
-                 return fold (build (MINUS_EXPR, type, tem, mask1));
+                 tem = fold (build2 (BIT_XOR_EXPR, type,
+                                     TREE_OPERAND (arg0, 0), mask1));
+                 return fold (build2 (MINUS_EXPR, type, tem, mask1));
                }
            }
        }
@@ -6313,7 +6394,7 @@ fold (tree expr)
       if (!wins && negate_expr_p (arg1)
          && (FLOAT_TYPE_P (type)
              || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
-       return fold (build (PLUS_EXPR, type, arg0, negate_expr (arg1)));
+       return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
 
       if (TREE_CODE (arg0) == MULT_EXPR
          && TREE_CODE (arg1) == MULT_EXPR
@@ -6322,19 +6403,19 @@ fold (tree expr)
           /* (A * C) - (B * C) -> (A-B) * C.  */
          if (operand_equal_p (TREE_OPERAND (arg0, 1),
                               TREE_OPERAND (arg1, 1), 0))
-           return fold (build (MULT_EXPR, type,
-                               fold (build (MINUS_EXPR, type,
-                                            TREE_OPERAND (arg0, 0),
-                                            TREE_OPERAND (arg1, 0))),
-                               TREE_OPERAND (arg0, 1)));
+           return fold (build2 (MULT_EXPR, type,
+                                fold (build2 (MINUS_EXPR, type,
+                                              TREE_OPERAND (arg0, 0),
+                                              TREE_OPERAND (arg1, 0))),
+                                TREE_OPERAND (arg0, 1)));
           /* (A * C1) - (A * C2) -> A * (C1-C2).  */
          if (operand_equal_p (TREE_OPERAND (arg0, 0),
                               TREE_OPERAND (arg1, 0), 0))
-           return fold (build (MULT_EXPR, type,
-                               TREE_OPERAND (arg0, 0),
-                               fold (build (MINUS_EXPR, type,
-                                            TREE_OPERAND (arg0, 1),
-                                            TREE_OPERAND (arg1, 1)))));
+           return fold (build2 (MULT_EXPR, type,
+                                TREE_OPERAND (arg0, 0),
+                                fold (build2 (MINUS_EXPR, type,
+                                              TREE_OPERAND (arg0, 1),
+                                              TREE_OPERAND (arg1, 1)))));
        }
 
       goto associate;
@@ -6342,13 +6423,13 @@ fold (tree expr)
     case MULT_EXPR:
       /* (-A) * (-B) -> A * B  */
       if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
-       return fold (build (MULT_EXPR, type,
-                           TREE_OPERAND (arg0, 0),
-                           negate_expr (arg1)));
+       return fold (build2 (MULT_EXPR, type,
+                            TREE_OPERAND (arg0, 0),
+                            negate_expr (arg1)));
       if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
-       return fold (build (MULT_EXPR, type,
-                           negate_expr (arg0),
-                           TREE_OPERAND (arg1, 0)));
+       return fold (build2 (MULT_EXPR, type,
+                            negate_expr (arg0),
+                            TREE_OPERAND (arg1, 0)));
 
       if (! FLOAT_TYPE_P (type))
        {
@@ -6360,12 +6441,12 @@ fold (tree expr)
          /* (a * (1 << b)) is (a << b)  */
          if (TREE_CODE (arg1) == LSHIFT_EXPR
              && integer_onep (TREE_OPERAND (arg1, 0)))
-           return fold (build (LSHIFT_EXPR, type, arg0,
-                               TREE_OPERAND (arg1, 1)));
+           return fold (build2 (LSHIFT_EXPR, type, arg0,
+                                TREE_OPERAND (arg1, 1)));
          if (TREE_CODE (arg0) == LSHIFT_EXPR
              && integer_onep (TREE_OPERAND (arg0, 0)))
-           return fold (build (LSHIFT_EXPR, type, arg1,
-                               TREE_OPERAND (arg0, 1)));
+           return fold (build2 (LSHIFT_EXPR, type, arg1,
+                                TREE_OPERAND (arg0, 1)));
 
          if (TREE_CODE (arg1) == INTEGER_CST
              && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0),
@@ -6392,7 +6473,7 @@ fold (tree expr)
          /* Transform x * -1.0 into -x.  */
          if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
              && real_minus_onep (arg1))
-           return fold (build1 (NEGATE_EXPR, type, arg0));
+           return fold_convert (type, negate_expr (arg0));
 
          /* Convert (C1/X)*C2 into (C1*C2)/X.  */
          if (flag_unsafe_math_optimizations
@@ -6403,8 +6484,8 @@ fold (tree expr)
              tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0),
                                      arg1, 0);
              if (tem)
-               return fold (build (RDIV_EXPR, type, tem,
-                                   TREE_OPERAND (arg0, 1)));
+               return fold (build2 (RDIV_EXPR, type, tem,
+                                    TREE_OPERAND (arg0, 1)));
            }
 
          if (flag_unsafe_math_optimizations)
@@ -6412,46 +6493,33 @@ fold (tree expr)
              enum built_in_function fcode0 = builtin_mathfn_code (arg0);
              enum built_in_function fcode1 = builtin_mathfn_code (arg1);
 
-             /* Optimizations of sqrt(...)*sqrt(...).  */
-             if ((fcode0 == BUILT_IN_SQRT && fcode1 == BUILT_IN_SQRT)
-                 || (fcode0 == BUILT_IN_SQRTF && fcode1 == BUILT_IN_SQRTF)
-                 || (fcode0 == BUILT_IN_SQRTL && fcode1 == BUILT_IN_SQRTL))
+             /* Optimizations of root(...)*root(...).  */
+             if (fcode0 == fcode1 && BUILTIN_ROOT_P (fcode0))
                {
-                 tree sqrtfn, arg, arglist;
+                 tree rootfn, arg, arglist;
                  tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
                  tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
 
                  /* Optimize sqrt(x)*sqrt(x) as x.  */
-                 if (operand_equal_p (arg00, arg10, 0)
+                 if (BUILTIN_SQRT_P (fcode0)
+                     && operand_equal_p (arg00, arg10, 0)
                      && ! HONOR_SNANS (TYPE_MODE (type)))
                    return arg00;
 
-                 /* Optimize sqrt(x)*sqrt(y) as sqrt(x*y).  */
-                 sqrtfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                 arg = fold (build (MULT_EXPR, type, arg00, arg10));
+                 /* Optimize root(x)*root(y) as root(x*y).  */
+                 rootfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+                 arg = fold (build2 (MULT_EXPR, type, arg00, arg10));
                  arglist = build_tree_list (NULL_TREE, arg);
-                 return build_function_call_expr (sqrtfn, arglist);
+                 return build_function_call_expr (rootfn, arglist);
                }
 
              /* Optimize expN(x)*expN(y) as expN(x+y).  */
-             if (fcode0 == fcode1
-                 && (fcode0 == BUILT_IN_EXP
-                     || fcode0 == BUILT_IN_EXPF
-                     || fcode0 == BUILT_IN_EXPL
-                     || fcode0 == BUILT_IN_EXP2
-                     || fcode0 == BUILT_IN_EXP2F
-                     || fcode0 == BUILT_IN_EXP2L
-                     || fcode0 == BUILT_IN_EXP10
-                     || fcode0 == BUILT_IN_EXP10F
-                     || fcode0 == BUILT_IN_EXP10L
-                     || fcode0 == BUILT_IN_POW10
-                     || fcode0 == BUILT_IN_POW10F
-                     || fcode0 == BUILT_IN_POW10L))
+             if (fcode0 == fcode1 && BUILTIN_EXPONENT_P (fcode0))
                {
                  tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                 tree arg = build (PLUS_EXPR, type,
-                                   TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                   TREE_VALUE (TREE_OPERAND (arg1, 1)));
+                 tree arg = build2 (PLUS_EXPR, type,
+                                    TREE_VALUE (TREE_OPERAND (arg0, 1)),
+                                    TREE_VALUE (TREE_OPERAND (arg1, 1)));
                  tree arglist = build_tree_list (NULL_TREE, fold (arg));
                  return build_function_call_expr (expfn, arglist);
                }
@@ -6472,7 +6540,7 @@ fold (tree expr)
                  if (operand_equal_p (arg01, arg11, 0))
                    {
                      tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                     tree arg = build (MULT_EXPR, type, arg00, arg10);
+                     tree arg = build2 (MULT_EXPR, type, arg00, arg10);
                      tree arglist = tree_cons (NULL_TREE, fold (arg),
                                                build_tree_list (NULL_TREE,
                                                                 arg01));
@@ -6483,7 +6551,7 @@ fold (tree expr)
                  if (operand_equal_p (arg00, arg10, 0))
                    {
                      tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                     tree arg = fold (build (PLUS_EXPR, type, arg01, arg11));
+                     tree arg = fold (build2 (PLUS_EXPR, type, arg01, arg11));
                      tree arglist = tree_cons (NULL_TREE, arg00,
                                                build_tree_list (NULL_TREE,
                                                                 arg));
@@ -6501,25 +6569,7 @@ fold (tree expr)
                  && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
                                      TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
                {
-                 tree sinfn;
-
-                 switch (fcode0)
-                   {
-                   case BUILT_IN_TAN:
-                   case BUILT_IN_COS:
-                     sinfn = implicit_built_in_decls[BUILT_IN_SIN];
-                     break;
-                   case BUILT_IN_TANF:
-                   case BUILT_IN_COSF:
-                     sinfn = implicit_built_in_decls[BUILT_IN_SINF];
-                     break;
-                   case BUILT_IN_TANL:
-                   case BUILT_IN_COSL:
-                     sinfn = implicit_built_in_decls[BUILT_IN_SINL];
-                     break;
-                   default:
-                     sinfn = NULL_TREE;
-                   }
+                 tree sinfn = mathfn_built_in (type, BUILT_IN_SIN);
 
                  if (sinfn != NULL_TREE)
                    return build_function_call_expr (sinfn,
@@ -6580,16 +6630,7 @@ fold (tree expr)
              if (! optimize_size
                  && operand_equal_p (arg0, arg1, 0))
                {
-                 tree powfn;
-
-                 if (type == double_type_node)
-                   powfn = implicit_built_in_decls[BUILT_IN_POW];
-                 else if (type == float_type_node)
-                   powfn = implicit_built_in_decls[BUILT_IN_POWF];
-                 else if (type == long_double_type_node)
-                   powfn = implicit_built_in_decls[BUILT_IN_POWL];
-                 else
-                   powfn = NULL_TREE;
+                 tree powfn = mathfn_built_in (type, BUILT_IN_POW);
 
                  if (powfn)
                    {
@@ -6609,6 +6650,8 @@ fold (tree expr)
        return omit_one_operand (type, arg1, arg0);
       if (integer_zerop (arg1))
        return non_lvalue (fold_convert (type, arg0));
+      if (operand_equal_p (arg0, arg1, 0))
+       return non_lvalue (fold_convert (type, arg0));
       t1 = distribute_bit_expr (code, type, arg0, arg1);
       if (t1 != NULL_TREE)
        return t1;
@@ -6623,9 +6666,9 @@ fold (tree expr)
          && TREE_CODE (arg1) == BIT_NOT_EXPR)
        {
          return fold (build1 (BIT_NOT_EXPR, type,
-                              build (BIT_AND_EXPR, type,
-                                     TREE_OPERAND (arg0, 0),
-                                     TREE_OPERAND (arg1, 0))));
+                              build2 (BIT_AND_EXPR, type,
+                                      TREE_OPERAND (arg0, 0),
+                                      TREE_OPERAND (arg1, 0))));
        }
 
       /* See if this can be simplified into a rotate first.  If that
@@ -6637,6 +6680,8 @@ fold (tree expr)
        return non_lvalue (fold_convert (type, arg0));
       if (integer_all_onesp (arg1))
        return fold (build1 (BIT_NOT_EXPR, type, arg0));
+      if (operand_equal_p (arg0, arg1, 0))
+       return omit_one_operand (type, integer_zero_node, arg0);
 
       /* If we are XORing two BIT_AND_EXPR's, both of which are and'ing
          with a constant, and the two constants have no bits in common,
@@ -6663,12 +6708,14 @@ fold (tree expr)
        return non_lvalue (fold_convert (type, arg0));
       if (integer_zerop (arg1))
        return omit_one_operand (type, arg1, arg0);
+      if (operand_equal_p (arg0, arg1, 0))
+       return non_lvalue (fold_convert (type, arg0));
       t1 = distribute_bit_expr (code, type, arg0, arg1);
       if (t1 != NULL_TREE)
        return t1;
       /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char.  */
       if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
-         && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+         && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
        {
          unsigned int prec
            = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
@@ -6689,9 +6736,9 @@ fold (tree expr)
          && TREE_CODE (arg1) == BIT_NOT_EXPR)
        {
          return fold (build1 (BIT_NOT_EXPR, type,
-                              build (BIT_IOR_EXPR, type,
-                                     TREE_OPERAND (arg0, 0),
-                                     TREE_OPERAND (arg1, 0))));
+                              build2 (BIT_IOR_EXPR, type,
+                                      TREE_OPERAND (arg0, 0),
+                                      TREE_OPERAND (arg1, 0))));
        }
 
       goto associate;
@@ -6706,13 +6753,13 @@ fold (tree expr)
 
       /* (-A) / (-B) -> A / B  */
       if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
-       return fold (build (RDIV_EXPR, type,
-                           TREE_OPERAND (arg0, 0),
-                           negate_expr (arg1)));
+       return fold (build2 (RDIV_EXPR, type,
+                            TREE_OPERAND (arg0, 0),
+                            negate_expr (arg1)));
       if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
-       return fold (build (RDIV_EXPR, type,
-                           negate_expr (arg0),
-                           TREE_OPERAND (arg1, 0)));
+       return fold (build2 (RDIV_EXPR, type,
+                            negate_expr (arg0),
+                            TREE_OPERAND (arg1, 0)));
 
       /* In IEEE floating point, x/1 is not equivalent to x for snans.  */
       if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
@@ -6734,7 +6781,7 @@ fold (tree expr)
          if (flag_unsafe_math_optimizations
              && 0 != (tem = const_binop (code, build_real (type, dconst1),
                                          arg1, 0)))
-           return fold (build (MULT_EXPR, type, arg0, tem));
+           return fold (build2 (MULT_EXPR, type, arg0, tem));
          /* Find the reciprocal if optimizing and the result is exact.  */
          if (optimize)
            {
@@ -6743,24 +6790,24 @@ fold (tree expr)
              if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
                {
                  tem = build_real (type, r);
-                 return fold (build (MULT_EXPR, type, arg0, tem));
+                 return fold (build2 (MULT_EXPR, type, arg0, tem));
                }
            }
        }
       /* Convert A/B/C to A/(B*C).  */
       if (flag_unsafe_math_optimizations
          && TREE_CODE (arg0) == RDIV_EXPR)
-       return fold (build (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
-                           fold (build (MULT_EXPR, type,
-                                        TREE_OPERAND (arg0, 1), arg1))));
+       return fold (build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
+                            fold (build2 (MULT_EXPR, type,
+                                          TREE_OPERAND (arg0, 1), arg1))));
 
       /* Convert A/(B/C) to (A/B)*C.  */
       if (flag_unsafe_math_optimizations
          && TREE_CODE (arg1) == RDIV_EXPR)
-       return fold (build (MULT_EXPR, type,
-                           fold (build (RDIV_EXPR, type, arg0,
-                                        TREE_OPERAND (arg1, 0))),
-                           TREE_OPERAND (arg1, 1)));
+       return fold (build2 (MULT_EXPR, type,
+                            fold (build2 (RDIV_EXPR, type, arg0,
+                                          TREE_OPERAND (arg1, 0))),
+                            TREE_OPERAND (arg1, 1)));
 
       /* Convert C1/(X*C2) into (C1/C2)/X.  */
       if (flag_unsafe_math_optimizations
@@ -6771,33 +6818,22 @@ fold (tree expr)
          tree tem = const_binop (RDIV_EXPR, arg0,
                                  TREE_OPERAND (arg1, 1), 0);
          if (tem)
-           return fold (build (RDIV_EXPR, type, tem,
-                               TREE_OPERAND (arg1, 0)));
+           return fold (build2 (RDIV_EXPR, type, tem,
+                                TREE_OPERAND (arg1, 0)));
        }
 
       if (flag_unsafe_math_optimizations)
        {
          enum built_in_function fcode = builtin_mathfn_code (arg1);
          /* Optimize x/expN(y) into x*expN(-y).  */
-         if (fcode == BUILT_IN_EXP
-             || fcode == BUILT_IN_EXPF
-             || fcode == BUILT_IN_EXPL
-             || fcode == BUILT_IN_EXP2
-             || fcode == BUILT_IN_EXP2F
-             || fcode == BUILT_IN_EXP2L
-             || fcode == BUILT_IN_EXP10
-             || fcode == BUILT_IN_EXP10F
-             || fcode == BUILT_IN_EXP10L
-             || fcode == BUILT_IN_POW10
-             || fcode == BUILT_IN_POW10F
-             || fcode == BUILT_IN_POW10L)
+         if (BUILTIN_EXPONENT_P (fcode))
            {
              tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
-             tree arg = build1 (NEGATE_EXPR, type,
-                                TREE_VALUE (TREE_OPERAND (arg1, 1)));
-             tree arglist = build_tree_list (NULL_TREE, fold (arg));
+             tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1)));
+             tree arglist = build_tree_list (NULL_TREE,
+                                             fold_convert (type, arg));
              arg1 = build_function_call_expr (expfn, arglist);
-             return fold (build (MULT_EXPR, type, arg0, arg1));
+             return fold (build2 (MULT_EXPR, type, arg0, arg1));
            }
 
          /* Optimize x/pow(y,z) into x*pow(y,-z).  */
@@ -6808,11 +6844,11 @@ fold (tree expr)
              tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
              tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
              tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
-             tree neg11 = fold (build1 (NEGATE_EXPR, type, arg11));
+             tree neg11 = fold_convert (type, negate_expr (arg11));
              tree arglist = tree_cons(NULL_TREE, arg10,
                                       build_tree_list (NULL_TREE, neg11));
              arg1 = build_function_call_expr (powfn, arglist);
-             return fold (build (MULT_EXPR, type, arg0, arg1));
+             return fold (build2 (MULT_EXPR, type, arg0, arg1));
            }
        }
 
@@ -6828,16 +6864,7 @@ fold (tree expr)
              && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
                                  TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
            {
-             tree tanfn;
-
-             if (fcode0 == BUILT_IN_SIN)
-               tanfn = implicit_built_in_decls[BUILT_IN_TAN];
-             else if (fcode0 == BUILT_IN_SINF)
-               tanfn = implicit_built_in_decls[BUILT_IN_TANF];
-             else if (fcode0 == BUILT_IN_SINL)
-               tanfn = implicit_built_in_decls[BUILT_IN_TANL];
-             else
-               tanfn = NULL_TREE;
+             tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
 
              if (tanfn != NULL_TREE)
                return build_function_call_expr (tanfn,
@@ -6851,24 +6878,14 @@ fold (tree expr)
              && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
                                  TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
            {
-             tree tanfn;
-
-             if (fcode0 == BUILT_IN_COS)
-               tanfn = implicit_built_in_decls[BUILT_IN_TAN];
-             else if (fcode0 == BUILT_IN_COSF)
-               tanfn = implicit_built_in_decls[BUILT_IN_TANF];
-             else if (fcode0 == BUILT_IN_COSL)
-               tanfn = implicit_built_in_decls[BUILT_IN_TANL];
-             else
-               tanfn = NULL_TREE;
+             tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
 
              if (tanfn != NULL_TREE)
                {
                  tree tmp = TREE_OPERAND (arg0, 1);
                  tmp = build_function_call_expr (tanfn, tmp);
-                 return fold (build (RDIV_EXPR, type,
-                                     build_real (type, dconst1),
-                                     tmp));
+                 return fold (build2 (RDIV_EXPR, type,
+                                      build_real (type, dconst1), tmp));
                }
            }
 
@@ -6907,6 +6924,12 @@ fold (tree expr)
        return non_lvalue (fold_convert (type, arg0));
       if (integer_zerop (arg1))
        return t;
+      /* X / -1 is -X.  */
+      if (!TYPE_UNSIGNED (type)
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
+         && TREE_INT_CST_HIGH (arg1) == -1)
+       return fold_convert (type, negate_expr (arg0));
 
       /* If arg0 is a multiple of arg1, then rewrite to the fastest div
         operation, EXACT_DIV_EXPR.
@@ -6916,7 +6939,7 @@ fold (tree expr)
         after the last round to changes to the DIV code in expmed.c.  */
       if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR)
          && multiple_of_p (type, arg0, arg1))
-       return fold (build (EXACT_DIV_EXPR, type, arg0, arg1));
+       return fold (build2 (EXACT_DIV_EXPR, type, arg0, arg1));
 
       if (TREE_CODE (arg1) == INTEGER_CST
          && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
@@ -6933,6 +6956,12 @@ fold (tree expr)
        return omit_one_operand (type, integer_zero_node, arg0);
       if (integer_zerop (arg1))
        return t;
+      /* X % -1 is zero.  */
+      if (!TYPE_UNSIGNED (type)
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
+         && TREE_INT_CST_HIGH (arg1) == -1)
+       return omit_one_operand (type, integer_zero_node, arg0);
 
       if (TREE_CODE (arg1) == INTEGER_CST
          && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
@@ -6949,7 +6978,7 @@ fold (tree expr)
 
     case RSHIFT_EXPR:
       /* Optimize -1 >> x for arithmetic right shifts.  */
-      if (integer_all_onesp (arg0) && ! TREE_UNSIGNED (type))
+      if (integer_all_onesp (arg0) && !TYPE_UNSIGNED (type))
        return omit_one_operand (type, arg0, arg1);
       /* ... fall through ...  */
 
@@ -6971,7 +7000,7 @@ fold (tree expr)
          tree tem = build_int_2 (GET_MODE_BITSIZE (TYPE_MODE (type)), 0);
          tem = fold_convert (TREE_TYPE (arg1), tem);
          tem = const_binop (MINUS_EXPR, tem, arg1, 0);
-         return fold (build (RROTATE_EXPR, type, arg0, tem));
+         return fold (build2 (RROTATE_EXPR, type, arg0, tem));
        }
 
       /* If we have a rotate of a bit operation with the rotate count and
@@ -6982,11 +7011,11 @@ fold (tree expr)
              || TREE_CODE (arg0) == BIT_IOR_EXPR
              || TREE_CODE (arg0) == BIT_XOR_EXPR)
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       return fold (build (TREE_CODE (arg0), type,
-                           fold (build (code, type,
-                                        TREE_OPERAND (arg0, 0), arg1)),
-                           fold (build (code, type,
-                                        TREE_OPERAND (arg0, 1), arg1))));
+       return fold (build2 (TREE_CODE (arg0), type,
+                            fold (build2 (code, type,
+                                          TREE_OPERAND (arg0, 0), arg1)),
+                            fold (build2 (code, type,
+                                          TREE_OPERAND (arg0, 1), arg1))));
 
       /* Two consecutive rotates adding up to the width of the mode can
         be ignored.  */
@@ -7006,7 +7035,7 @@ fold (tree expr)
       if (operand_equal_p (arg0, arg1, 0))
        return omit_one_operand (type, arg0, arg1);
       if (INTEGRAL_TYPE_P (type)
-         && operand_equal_p (arg1, TYPE_MIN_VALUE (type), 1))
+         && operand_equal_p (arg1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST))
        return omit_one_operand (type, arg1, arg0);
       goto associate;
 
@@ -7015,7 +7044,7 @@ fold (tree expr)
        return omit_one_operand (type, arg0, arg1);
       if (INTEGRAL_TYPE_P (type)
          && TYPE_MAX_VALUE (type)
-         && operand_equal_p (arg1, TYPE_MAX_VALUE (type), 1))
+         && operand_equal_p (arg1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST))
        return omit_one_operand (type, arg1, arg0);
       goto associate;
 
@@ -7087,23 +7116,23 @@ fold (tree expr)
                                 || code == TRUTH_OR_EXPR));
 
          if (operand_equal_p (a00, a10, 0))
-           return fold (build (TREE_CODE (arg0), type, a00,
-                               fold (build (code, type, a01, a11))));
+           return fold (build2 (TREE_CODE (arg0), type, a00,
+                                fold (build2 (code, type, a01, a11))));
          else if (commutative && operand_equal_p (a00, a11, 0))
-           return fold (build (TREE_CODE (arg0), type, a00,
-                               fold (build (code, type, a01, a10))));
+           return fold (build2 (TREE_CODE (arg0), type, a00,
+                                fold (build2 (code, type, a01, a10))));
          else if (commutative && operand_equal_p (a01, a10, 0))
-           return fold (build (TREE_CODE (arg0), type, a01,
-                               fold (build (code, type, a00, a11))));
+           return fold (build2 (TREE_CODE (arg0), type, a01,
+                                fold (build2 (code, type, a00, a11))));
 
          /* This case if tricky because we must either have commutative
             operators or else A10 must not have side-effects.  */
 
          else if ((commutative || ! TREE_SIDE_EFFECTS (a10))
                   && operand_equal_p (a01, a11, 0))
-           return fold (build (TREE_CODE (arg0), type,
-                               fold (build (code, type, a00, a10)),
-                               a01));
+           return fold (build2 (TREE_CODE (arg0), type,
+                                fold (build2 (code, type, a00, a10)),
+                                a01));
        }
 
       /* See if we can build a range comparison.  */
@@ -7116,7 +7145,7 @@ fold (tree expr)
       if (TREE_CODE (arg0) == code
          && 0 != (tem = fold_truthop (code, type,
                                       TREE_OPERAND (arg0, 1), arg1)))
-       return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
+       return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
 
       if ((tem = fold_truthop (code, type, arg0, arg1)) != 0)
        return tem;
@@ -7159,6 +7188,9 @@ fold (tree expr)
        return non_lvalue (fold_convert (type, invert_truthvalue (arg1)));
       if (integer_onep (arg1))
        return non_lvalue (fold_convert (type, invert_truthvalue (arg0)));
+      /* Identical arguments cancel to zero.  */
+      if (operand_equal_p (arg0, arg1, 0))
+       return omit_one_operand (type, integer_zero_node, arg0);
       return t;
 
     case EQ_EXPR:
@@ -7169,27 +7201,66 @@ fold (tree expr)
     case GE_EXPR:
       /* If one arg is a real or integer constant, put it last.  */
       if (tree_swap_operands_p (arg0, arg1, true))
-       return fold (build (swap_tree_comparison (code), type, arg1, arg0));
+       return fold (build2 (swap_tree_comparison (code), type, arg1, arg0));
 
-      if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
+      /* If this is an equality comparison of the address of a non-weak
+        object against zero, then we know the result.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+         && TREE_CODE (arg0) == ADDR_EXPR
+         && DECL_P (TREE_OPERAND (arg0, 0))
+         && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
+         && integer_zerop (arg1))
        {
-         tree targ0 = strip_float_extensions (arg0);
-         tree targ1 = strip_float_extensions (arg1);
-         tree newtype = TREE_TYPE (targ0);
+         if (code == EQ_EXPR)
+           return fold_convert (type, integer_zero_node);
+         else
+           return fold_convert (type, integer_one_node);
+       }
 
-         if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
-           newtype = TREE_TYPE (targ1);
+      /* If this is an equality comparison of the address of two non-weak,
+        unaliased symbols neither of which are extern (since we do not
+        have access to attributes for externs), then we know the result.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+         && TREE_CODE (arg0) == ADDR_EXPR
+         && DECL_P (TREE_OPERAND (arg0, 0))
+         && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
+         && ! lookup_attribute ("alias",
+                                DECL_ATTRIBUTES (TREE_OPERAND (arg0, 0)))
+         && ! DECL_EXTERNAL (TREE_OPERAND (arg0, 0))
+         && TREE_CODE (arg1) == ADDR_EXPR
+         && DECL_P (TREE_OPERAND (arg1, 0))
+         && ! DECL_WEAK (TREE_OPERAND (arg1, 0))
+         && ! lookup_attribute ("alias",
+                                DECL_ATTRIBUTES (TREE_OPERAND (arg1, 0)))
+         && ! DECL_EXTERNAL (TREE_OPERAND (arg1, 0)))
+       {
+         if (code == EQ_EXPR)
+           return fold_convert (type, (operand_equal_p (arg0, arg1, 0)
+                   ? integer_one_node : integer_zero_node));
+         else
+           return fold_convert (type, (operand_equal_p (arg0, arg1, 0)
+                   ? integer_zero_node : integer_one_node));
+       }
+
+      if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
+       {
+         tree targ0 = strip_float_extensions (arg0);
+         tree targ1 = strip_float_extensions (arg1);
+         tree newtype = TREE_TYPE (targ0);
+
+         if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
+           newtype = TREE_TYPE (targ1);
 
          /* Fold (double)float1 CMP (double)float2 into float1 CMP float2.  */
          if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
-           return fold (build (code, type, fold_convert (newtype, targ0),
-                               fold_convert (newtype, targ1)));
+           return fold (build2 (code, type, fold_convert (newtype, targ0),
+                                fold_convert (newtype, targ1)));
 
          /* (-a) CMP (-b) -> b CMP a  */
          if (TREE_CODE (arg0) == NEGATE_EXPR
              && TREE_CODE (arg1) == NEGATE_EXPR)
-           return fold (build (code, type, TREE_OPERAND (arg1, 0),
-                               TREE_OPERAND (arg0, 0)));
+           return fold (build2 (code, type, TREE_OPERAND (arg1, 0),
+                                TREE_OPERAND (arg0, 0)));
 
          if (TREE_CODE (arg1) == REAL_CST)
          {
@@ -7199,23 +7270,23 @@ fold (tree expr)
            /* (-a) CMP CST -> a swap(CMP) (-CST)  */
            if (TREE_CODE (arg0) == NEGATE_EXPR)
              return
-               fold (build (swap_tree_comparison (code), type,
-                            TREE_OPERAND (arg0, 0),
-                            build_real (TREE_TYPE (arg1),
-                                        REAL_VALUE_NEGATE (cst))));
+               fold (build2 (swap_tree_comparison (code), type,
+                             TREE_OPERAND (arg0, 0),
+                             build_real (TREE_TYPE (arg1),
+                                         REAL_VALUE_NEGATE (cst))));
 
            /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
            /* a CMP (-0) -> a CMP 0  */
            if (REAL_VALUE_MINUS_ZERO (cst))
-             return fold (build (code, type, arg0,
-                                 build_real (TREE_TYPE (arg1), dconst0)));
+             return fold (build2 (code, type, arg0,
+                                  build_real (TREE_TYPE (arg1), dconst0)));
 
            /* x != NaN is always true, other ops are always false.  */
            if (REAL_VALUE_ISNAN (cst)
                && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
              {
-               t = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
-               return omit_one_operand (type, fold_convert (type, t), arg0);
+               tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
+               return omit_one_operand (type, fold_convert (type, tem), arg0);
              }
 
            /* Fold comparisons against infinity.  */
@@ -7240,7 +7311,7 @@ fold (tree expr)
                                          ? MINUS_EXPR : PLUS_EXPR,
                                          arg1, TREE_OPERAND (arg0, 1), 0))
              && ! TREE_CONSTANT_OVERFLOW (tem))
-           return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
+           return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
 
          /* Likewise, we can simplify a comparison of a real constant with
             a MINUS_EXPR whose first operand is also a real constant, i.e.
@@ -7252,8 +7323,8 @@ fold (tree expr)
              && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
                                          arg1, 0))
              && ! TREE_CONSTANT_OVERFLOW (tem))
-           return fold (build (swap_tree_comparison (code), type,
-                               TREE_OPERAND (arg0, 1), tem));
+           return fold (build2 (swap_tree_comparison (code), type,
+                                TREE_OPERAND (arg0, 1), tem));
 
          /* Fold comparisons against built-in math functions.  */
          if (TREE_CODE (arg1) == REAL_CST
@@ -7271,150 +7342,67 @@ fold (tree expr)
            }
        }
 
-      /* Convert foo++ == CONST into ++foo == CONST + INCR.
-        First, see if one arg is constant; find the constant arg
-        and the other one.  */
-      {
-       tree constop = 0, varop = NULL_TREE;
-       int constopnum = -1;
+      /* 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_CONSTANT (arg1))
-         constopnum = 1, constop = arg1, varop = arg0;
-       if (TREE_CONSTANT (arg0))
-         constopnum = 0, constop = arg0, varop = arg1;
+         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 (constop && TREE_CODE (varop) == POSTINCREMENT_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.  */
-           if (POINTER_TYPE_P (TREE_TYPE (varop))
-               || (! FLOAT_TYPE_P (TREE_TYPE (varop))
-                   && (code == EQ_EXPR || code == NE_EXPR)))
-             {
-               tree newconst
-                 = fold (build (PLUS_EXPR, TREE_TYPE (varop),
-                                constop, TREE_OPERAND (varop, 1)));
-
-               /* Do not overwrite the current varop to be a preincrement,
-                  create a new node so that we won't confuse our caller who
-                  might create trees and throw them away, reusing the
-                  arguments that they passed to build.  This shows up in
-                  the THEN or ELSE parts of ?: being postincrements.  */
-               varop = build (PREINCREMENT_EXPR, TREE_TYPE (varop),
-                              TREE_OPERAND (varop, 0),
-                              TREE_OPERAND (varop, 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)))
-                 {
-                   int size
-                     = TREE_INT_CST_LOW (DECL_SIZE
-                                         (TREE_OPERAND
-                                          (TREE_OPERAND (varop, 0), 1)));
-                   tree mask, unsigned_type;
-                   unsigned int precision;
-                   tree folded_compare;
-
-                   /* 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.  */
-                   if (constopnum == 0)
-                     folded_compare = fold (build (code, type, constop,
-                                                   TREE_OPERAND (varop, 0)));
-                   else
-                     folded_compare = fold (build (code, type,
-                                                   TREE_OPERAND (varop, 0),
-                                                   constop));
-                   if (integer_zerop (folded_compare)
-                       || integer_onep (folded_compare))
-                     return omit_one_operand (type, folded_compare, varop);
-
-                   unsigned_type = (*lang_hooks.types.type_for_size)(size, 1);
-                   precision = TYPE_PRECISION (unsigned_type);
-                   mask = build_int_2 (~0, ~0);
-                   TREE_TYPE (mask) = unsigned_type;
-                   force_fit_type (mask, 0);
-                   mask = const_binop (RSHIFT_EXPR, mask,
-                                       size_int (precision - size), 0);
-                   newconst = fold (build (BIT_AND_EXPR,
-                                           TREE_TYPE (varop), newconst,
-                                           fold_convert (TREE_TYPE (varop),
-                                                         mask)));
-                 }
 
-               t = build (code, type,
-                          (constopnum == 0) ? newconst : varop,
-                          (constopnum == 1) ? newconst : varop);
-               return t;
-             }
-         }
-       else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
-         {
-           if (POINTER_TYPE_P (TREE_TYPE (varop))
-               || (! FLOAT_TYPE_P (TREE_TYPE (varop))
-                   && (code == EQ_EXPR || code == NE_EXPR)))
-             {
-               tree newconst
-                 = fold (build (MINUS_EXPR, TREE_TYPE (varop),
-                                constop, TREE_OPERAND (varop, 1)));
-
-               /* Do not overwrite the current varop to be a predecrement,
-                  create a new node so that we won't confuse our caller who
-                  might create trees and throw them away, reusing the
-                  arguments that they passed to build.  This shows up in
-                  the THEN or ELSE parts of ?: being postdecrements.  */
-               varop = build (PREDECREMENT_EXPR, TREE_TYPE (varop),
-                              TREE_OPERAND (varop, 0),
-                              TREE_OPERAND (varop, 1));
-
-               if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
-                   && DECL_BIT_FIELD(TREE_OPERAND
-                                     (TREE_OPERAND (varop, 0), 1)))
-                 {
-                   int size
-                     = TREE_INT_CST_LOW (DECL_SIZE
-                                         (TREE_OPERAND
-                                          (TREE_OPERAND (varop, 0), 1)));
-                   tree mask, unsigned_type;
-                   unsigned int precision;
-                   tree folded_compare;
-
-                   if (constopnum == 0)
-                     folded_compare = fold (build (code, type, constop,
-                                                   TREE_OPERAND (varop, 0)));
-                   else
-                     folded_compare = fold (build (code, type,
-                                                   TREE_OPERAND (varop, 0),
-                                                   constop));
-                   if (integer_zerop (folded_compare)
-                       || integer_onep (folded_compare))
-                     return omit_one_operand (type, folded_compare, varop);
-
-                   unsigned_type = (*lang_hooks.types.type_for_size)(size, 1);
-                   precision = TYPE_PRECISION (unsigned_type);
-                   mask = build_int_2 (~0, ~0);
-                   TREE_TYPE (mask) = TREE_TYPE (varop);
-                   force_fit_type (mask, 0);
-                   mask = const_binop (RSHIFT_EXPR, mask,
-                                       size_int (precision - size), 0);
-                   newconst = fold (build (BIT_AND_EXPR,
-                                           TREE_TYPE (varop), newconst,
-                                           fold_convert (TREE_TYPE (varop),
-                                                         mask)));
-                 }
+         /* 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)))
+           {
+             tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
+             int size = TREE_INT_CST_LOW (DECL_SIZE (fielddecl));
+             tree folded_compare, shift;
+
+             /* First check whether the comparison would come out
+                always the same.  If we don't do that we would
+                change the meaning with the masking.  */
+             folded_compare = fold (build2 (code, type,
+                                            TREE_OPERAND (varop, 0),
+                                            arg1));
+             if (integer_zerop (folded_compare)
+                 || integer_onep (folded_compare))
+               return omit_one_operand (type, folded_compare, varop);
+
+             shift = build_int_2 (TYPE_PRECISION (TREE_TYPE (varop)) - size,
+                                  0);
+             newconst = fold (build2 (LSHIFT_EXPR, TREE_TYPE (varop),
+                                      newconst, shift));
+             newconst = fold (build2 (RSHIFT_EXPR, TREE_TYPE (varop),
+                                      newconst, shift));
+           }
 
-               t = build (code, type,
-                          (constopnum == 0) ? newconst : varop,
-                          (constopnum == 1) ? newconst : varop);
-               return t;
-             }
-         }
-      }
+         return fold (build2 (code, type, varop, newconst));
+       }
 
       /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
         This transformation affects the cases which are handled in later
@@ -7427,11 +7415,11 @@ fold (tree expr)
            {
            case GE_EXPR:
              arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-             return fold (build (GT_EXPR, type, arg0, arg1));
+             return fold (build2 (GT_EXPR, type, arg0, arg1));
 
            case LT_EXPR:
              arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-             return fold (build (LE_EXPR, type, arg0, arg1));
+             return fold (build2 (LE_EXPR, type, arg0, arg1));
 
            default:
              break;
@@ -7439,7 +7427,11 @@ fold (tree expr)
        }
 
       /* Comparisons with the highest or lowest possible integer of
-        the specified size will have known values.  */
+        the specified size will have known values. 
+
+        This is quite similar to fold_relational_hi_lo; however, my
+        attempts to share the code have been nothing but trouble.
+        I give up for now.  */
       {
        int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg1)));
 
@@ -7454,7 +7446,7 @@ fold (tree expr)
 
            signed_max = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1;
 
-           if (TREE_UNSIGNED (TREE_TYPE (arg1)))
+           if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
              {
                max = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
                min = 0;
@@ -7475,7 +7467,7 @@ fold (tree expr)
                                                         integer_zero_node),
                                           arg0);
                case GE_EXPR:
-                 return fold (build (EQ_EXPR, type, arg0, arg1));
+                 return fold (build2 (EQ_EXPR, type, arg0, arg1));
 
                case LE_EXPR:
                  return omit_one_operand (type,
@@ -7483,7 +7475,7 @@ fold (tree expr)
                                                         integer_one_node),
                                           arg0);
                case LT_EXPR:
-                 return fold (build (NE_EXPR, type, arg0, arg1));
+                 return fold (build2 (NE_EXPR, type, arg0, arg1));
 
                /* The GE_EXPR and LT_EXPR cases above are not normally
                   reached because of previous transformations.  */
@@ -7497,10 +7489,10 @@ fold (tree expr)
                {
                case GT_EXPR:
                  arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
-                 return fold (build (EQ_EXPR, type, arg0, arg1));
+                 return fold (build2 (EQ_EXPR, type, arg0, arg1));
                case LE_EXPR:
                  arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
-                 return fold (build (NE_EXPR, type, arg0, arg1));
+                 return fold (build2 (NE_EXPR, type, arg0, arg1));
                default:
                  break;
                }
@@ -7514,7 +7506,7 @@ fold (tree expr)
                                                         integer_zero_node),
                                           arg0);
                case LE_EXPR:
-                 return fold (build (EQ_EXPR, type, arg0, arg1));
+                 return fold (build2 (EQ_EXPR, type, arg0, arg1));
 
                case GE_EXPR:
                  return omit_one_operand (type,
@@ -7522,7 +7514,7 @@ fold (tree expr)
                                                         integer_one_node),
                                           arg0);
                case GT_EXPR:
-                 return fold (build (NE_EXPR, type, arg0, arg1));
+                 return fold (build2 (NE_EXPR, type, arg0, arg1));
 
                default:
                  break;
@@ -7533,17 +7525,18 @@ fold (tree expr)
                {
                case GE_EXPR:
                  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold (build (NE_EXPR, type, arg0, arg1));
+                 return fold (build2 (NE_EXPR, type, arg0, arg1));
                case LT_EXPR:
                  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold (build (EQ_EXPR, type, arg0, arg1));
+                 return fold (build2 (EQ_EXPR, type, arg0, arg1));
                default:
                  break;
                }
 
-           else if (TREE_INT_CST_HIGH (arg1) == 0
+           else if (!in_gimple_form
+                    && TREE_INT_CST_HIGH (arg1) == 0
                     && TREE_INT_CST_LOW (arg1) == signed_max
-                    && TREE_UNSIGNED (TREE_TYPE (arg1))
+                    && TYPE_UNSIGNED (TREE_TYPE (arg1))
                     /* signed_type does not work on pointer types.  */
                     && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
              {
@@ -7552,12 +7545,12 @@ fold (tree expr)
                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));
+                   st0 = lang_hooks.types.signed_type (TREE_TYPE (arg0));
+                   st1 = lang_hooks.types.signed_type (TREE_TYPE (arg1));
                    return fold
-                     (build (code == LE_EXPR ? GE_EXPR: LT_EXPR,
-                             type, fold_convert (st0, arg0),
-                             fold_convert (st1, integer_zero_node)));
+                     (build2 (code == LE_EXPR ? GE_EXPR: LT_EXPR,
+                              type, fold_convert (st0, arg0),
+                              fold_convert (st1, integer_zero_node)));
                  }
              }
          }
@@ -7575,7 +7568,7 @@ fold (tree expr)
                                      ? MINUS_EXPR : PLUS_EXPR,
                                      arg1, TREE_OPERAND (arg0, 1), 0))
          && ! TREE_CONSTANT_OVERFLOW (tem))
-       return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
+       return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
 
       /* Similarly for a NEGATE_EXPR.  */
       else if ((code == EQ_EXPR || code == NE_EXPR)
@@ -7584,14 +7577,14 @@ fold (tree expr)
               && 0 != (tem = negate_expr (arg1))
               && TREE_CODE (tem) == INTEGER_CST
               && ! TREE_CONSTANT_OVERFLOW (tem))
-       return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
+       return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
 
       /* If we have X - Y == 0, we can convert that to X == Y and similarly
         for !=.  Don't do this for ordered comparisons due to overflow.  */
       else if ((code == NE_EXPR || code == EQ_EXPR)
               && integer_zerop (arg1) && TREE_CODE (arg0) == MINUS_EXPR)
-       return fold (build (code, type,
-                           TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)));
+       return fold (build2 (code, type,
+                            TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)));
 
       /* If we are widening one operand of an integer comparison,
         see if the other operand is similarly being widened.  Perhaps we
@@ -7599,12 +7592,15 @@ fold (tree expr)
       else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
               && TREE_CODE (arg0) == NOP_EXPR
               && (tem = get_unwidened (arg0, NULL_TREE)) != arg0
+              && (code == EQ_EXPR || code == NE_EXPR
+                  || TYPE_UNSIGNED (TREE_TYPE (arg0))
+                     == TYPE_UNSIGNED (TREE_TYPE (tem)))
               && (t1 = get_unwidened (arg1, TREE_TYPE (tem))) != 0
               && (TREE_TYPE (t1) == TREE_TYPE (tem)
                   || (TREE_CODE (t1) == INTEGER_CST
                       && int_fits_type_p (t1, TREE_TYPE (tem)))))
-       return fold (build (code, type, tem,
-                           fold_convert (TREE_TYPE (tem), t1)));
+       return fold (build2 (code, type, tem,
+                            fold_convert (TREE_TYPE (tem), t1)));
 
       /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a
         constant, we can simplify it.  */
@@ -7625,10 +7621,11 @@ fold (tree expr)
               && (0 != (tem = negate_expr (arg1)))
               && TREE_CODE (tem) == INTEGER_CST
               && ! TREE_CONSTANT_OVERFLOW (tem))
-       return fold (build (TRUTH_ANDIF_EXPR, type,
-                           build (GE_EXPR, type, TREE_OPERAND (arg0, 0), tem),
-                           build (LE_EXPR, type,
-                                  TREE_OPERAND (arg0, 0), arg1)));
+       return fold (build2 (TRUTH_ANDIF_EXPR, type,
+                            build2 (GE_EXPR, type,
+                                    TREE_OPERAND (arg0, 0), tem),
+                            build2 (LE_EXPR, type,
+                                    TREE_OPERAND (arg0, 0), arg1)));
 
       /* If this is an EQ or NE comparison with zero and ARG0 is
         (1 << foo) & bar, convert it to (bar >> foo) & 1.  Both require
@@ -7638,30 +7635,28 @@ fold (tree expr)
       if (integer_zerop (arg1) && (code == EQ_EXPR || code == NE_EXPR)
          && TREE_CODE (arg0) == BIT_AND_EXPR)
        {
-         if (TREE_CODE (TREE_OPERAND (arg0, 0)) == LSHIFT_EXPR
-             && integer_onep (TREE_OPERAND (TREE_OPERAND (arg0, 0), 0)))
+         tree arg00 = TREE_OPERAND (arg0, 0);
+         tree arg01 = TREE_OPERAND (arg0, 1);
+         if (TREE_CODE (arg00) == LSHIFT_EXPR
+             && integer_onep (TREE_OPERAND (arg00, 0)))
            return
-             fold (build (code, type,
-                          build (BIT_AND_EXPR, TREE_TYPE (arg0),
-                                 build (RSHIFT_EXPR,
-                                        TREE_TYPE (TREE_OPERAND (arg0, 0)),
-                                        TREE_OPERAND (arg0, 1),
-                                        TREE_OPERAND (TREE_OPERAND (arg0, 0), 1)),
-                                 fold_convert (TREE_TYPE (arg0),
-                                               integer_one_node)),
-                          arg1));
+             fold (build2 (code, type,
+                           build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                                   build2 (RSHIFT_EXPR, TREE_TYPE (arg00),
+                                           arg01, TREE_OPERAND (arg00, 1)),
+                                   fold_convert (TREE_TYPE (arg0),
+                                                 integer_one_node)),
+                           arg1));
          else if (TREE_CODE (TREE_OPERAND (arg0, 1)) == LSHIFT_EXPR
                   && integer_onep (TREE_OPERAND (TREE_OPERAND (arg0, 1), 0)))
            return
-             fold (build (code, type,
-                          build (BIT_AND_EXPR, TREE_TYPE (arg0),
-                                 build (RSHIFT_EXPR,
-                                        TREE_TYPE (TREE_OPERAND (arg0, 1)),
-                                        TREE_OPERAND (arg0, 0),
-                                        TREE_OPERAND (TREE_OPERAND (arg0, 1), 1)),
-                                 fold_convert (TREE_TYPE (arg0),
-                                               integer_one_node)),
-                          arg1));
+             fold (build2 (code, type,
+                           build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                                   build2 (RSHIFT_EXPR, TREE_TYPE (arg01),
+                                           arg00, TREE_OPERAND (arg01, 1)),
+                                   fold_convert (TREE_TYPE (arg0),
+                                                 integer_one_node)),
+                           arg1));
        }
 
       /* If this is an NE or EQ comparison of zero against the result of a
@@ -7669,21 +7664,21 @@ fold (tree expr)
         the MOD operation unsigned since it is simpler and equivalent.  */
       if ((code == NE_EXPR || code == EQ_EXPR)
          && integer_zerop (arg1)
-         && ! TREE_UNSIGNED (TREE_TYPE (arg0))
+         && !TYPE_UNSIGNED (TREE_TYPE (arg0))
          && (TREE_CODE (arg0) == TRUNC_MOD_EXPR
              || TREE_CODE (arg0) == CEIL_MOD_EXPR
              || TREE_CODE (arg0) == FLOOR_MOD_EXPR
              || TREE_CODE (arg0) == ROUND_MOD_EXPR)
          && integer_pow2p (TREE_OPERAND (arg0, 1)))
        {
-         tree newtype = (*lang_hooks.types.unsigned_type) (TREE_TYPE (arg0));
-         tree newmod = build (TREE_CODE (arg0), newtype,
-                              fold_convert (newtype,
-                                            TREE_OPERAND (arg0, 0)),
-                              fold_convert (newtype,
-                                            TREE_OPERAND (arg0, 1)));
-
-         return build (code, type, newmod, fold_convert (newtype, arg1));
+         tree newtype = lang_hooks.types.unsigned_type (TREE_TYPE (arg0));
+         tree newmod = build2 (TREE_CODE (arg0), newtype,
+                               fold_convert (newtype,
+                                             TREE_OPERAND (arg0, 0)),
+                               fold_convert (newtype,
+                                             TREE_OPERAND (arg0, 1)));
+
+         return build2 (code, type, newmod, fold_convert (newtype, arg1));
        }
 
       /* If this is an NE comparison of zero with an AND of one, remove the
@@ -7699,8 +7694,8 @@ fold (tree expr)
          && TREE_CODE (arg0) == BIT_AND_EXPR
          && integer_pow2p (TREE_OPERAND (arg0, 1))
          && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
-       return fold (build (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
-                           arg0, integer_zero_node));
+       return fold (build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
+                            arg0, integer_zero_node));
 
       /* If we have (A & C) != 0 or (A & C) == 0 and C is a power of
         2, then fold the expression into shifts and logical operations.  */
@@ -7716,10 +7711,10 @@ fold (tree expr)
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
        {
          tree dandnotc
-           = fold (build (BIT_AND_EXPR, TREE_TYPE (arg0),
-                          arg1, build1 (BIT_NOT_EXPR,
-                                        TREE_TYPE (TREE_OPERAND (arg0, 1)),
-                                        TREE_OPERAND (arg0, 1))));
+           = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                           arg1, build1 (BIT_NOT_EXPR,
+                                         TREE_TYPE (TREE_OPERAND (arg0, 1)),
+                                         TREE_OPERAND (arg0, 1))));
          tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
          if (integer_nonzerop (dandnotc))
            return omit_one_operand (type, rslt, arg0);
@@ -7733,9 +7728,9 @@ fold (tree expr)
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
        {
          tree candnotd
-           = fold (build (BIT_AND_EXPR, TREE_TYPE (arg0),
-                          TREE_OPERAND (arg0, 1),
-                          build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1)));
+           = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                           TREE_OPERAND (arg0, 1),
+                           build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1)));
          tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
          if (integer_nonzerop (candnotd))
            return omit_one_operand (type, rslt, arg0);
@@ -7744,27 +7739,27 @@ fold (tree expr)
       /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
         and similarly for >= into !=.  */
       if ((code == LT_EXPR || code == GE_EXPR)
-         && TREE_UNSIGNED (TREE_TYPE (arg0))
+         && TYPE_UNSIGNED (TREE_TYPE (arg0))
          && TREE_CODE (arg1) == LSHIFT_EXPR
          && integer_onep (TREE_OPERAND (arg1, 0)))
-       return build (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
-                     build (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
-                            TREE_OPERAND (arg1, 1)),
-                     fold_convert (TREE_TYPE (arg0), integer_zero_node));
+       return build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+                      build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+                              TREE_OPERAND (arg1, 1)),
+                      fold_convert (TREE_TYPE (arg0), integer_zero_node));
 
       else if ((code == LT_EXPR || code == GE_EXPR)
-              && TREE_UNSIGNED (TREE_TYPE (arg0))
+              && TYPE_UNSIGNED (TREE_TYPE (arg0))
               && (TREE_CODE (arg1) == NOP_EXPR
                   || TREE_CODE (arg1) == CONVERT_EXPR)
               && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
               && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
        return
-         build (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
-                fold_convert (TREE_TYPE (arg0),
-                              build (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
-                                     TREE_OPERAND (TREE_OPERAND (arg1, 0),
-                                                   1))),
-                fold_convert (TREE_TYPE (arg0), integer_zero_node));
+         build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+                 fold_convert (TREE_TYPE (arg0),
+                               build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+                                       TREE_OPERAND (TREE_OPERAND (arg1, 0),
+                                                     1))),
+                 fold_convert (TREE_TYPE (arg0), integer_zero_node));
 
       /* Simplify comparison of something with itself.  (For IEEE
         floating-point, we can only do some of these simplifications.)  */
@@ -7783,7 +7778,7 @@ fold (tree expr)
              if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
                  || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
                return constant_boolean_node (1, type);
-             return fold (build (EQ_EXPR, type, arg0, arg1));
+             return fold (build2 (EQ_EXPR, type, arg0, arg1));
 
            case NE_EXPR:
              /* For NE, we can only do this simplification if integer
@@ -7837,17 +7832,20 @@ fold (tree expr)
                 was the same as ARG1.  */
 
              tree high_result
-               = fold (build (code, type,
-                              eval_subst (arg0, cval1, maxval, cval2, minval),
-                              arg1));
+               = fold (build2 (code, type,
+                               eval_subst (arg0, cval1, maxval,
+                                           cval2, minval),
+                               arg1));
              tree equal_result
-               = fold (build (code, type,
-                              eval_subst (arg0, cval1, maxval, cval2, maxval),
-                              arg1));
+               = fold (build2 (code, type,
+                               eval_subst (arg0, cval1, maxval,
+                                           cval2, maxval),
+                               arg1));
              tree low_result
-               = fold (build (code, type,
-                              eval_subst (arg0, cval1, minval, cval2, maxval),
-                              arg1));
+               = fold (build2 (code, type,
+                               eval_subst (arg0, cval1, minval,
+                                           cval2, maxval),
+                               arg1));
 
              /* All three of these results should be 0 or 1.  Confirm they
                 are.  Then use those values to select the proper code
@@ -7892,18 +7890,18 @@ fold (tree expr)
                      return omit_one_operand (type, integer_one_node, arg0);
                    }
 
-                 t = build (code, type, cval1, cval2);
+                 tem = build2 (code, type, cval1, cval2);
                  if (save_p)
-                   return save_expr (t);
+                   return save_expr (tem);
                  else
-                   return fold (t);
+                   return fold (tem);
                }
            }
        }
 
       /* If this is a comparison of a field, we may be able to simplify it.  */
       if (((TREE_CODE (arg0) == COMPONENT_REF
-           && (*lang_hooks.can_use_bit_fields_p) ())
+           && lang_hooks.can_use_bit_fields_p ())
           || TREE_CODE (arg0) == BIT_FIELD_REF)
          && (code == EQ_EXPR || code == NE_EXPR)
          /* Handle the constant case even without -O
@@ -7936,11 +7934,11 @@ fold (tree expr)
          real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
          imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
 
-         return fold (build ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
-                              : TRUTH_ORIF_EXPR),
-                             type,
-                             fold (build (code, type, real0, real1)),
-                             fold (build (code, type, imag0, imag1))));
+         return fold (build2 ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
+                               : TRUTH_ORIF_EXPR),
+                              type,
+                              fold (build2 (code, type, real0, real1)),
+                              fold (build2 (code, type, imag0, imag1))));
        }
 
       /* Optimize comparisons of strlen vs zero to a compare of the
@@ -7963,98 +7961,29 @@ fold (tree expr)
              && (arglist = TREE_OPERAND (arg0, 1))
              && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
              && ! TREE_CHAIN (arglist))
-           return fold (build (code, type,
-                               build1 (INDIRECT_REF, char_type_node,
-                                       TREE_VALUE(arglist)),
-                               integer_zero_node));
+           return fold (build2 (code, type,
+                                build1 (INDIRECT_REF, char_type_node,
+                                        TREE_VALUE(arglist)),
+                                integer_zero_node));
        }
 
-      /* From here on, the only cases we handle are when the result is
-        known to be a constant.
-
-        To compute GT, swap the arguments and do LT.
-        To compute GE, do LT and invert the result.
-        To compute LE, swap the arguments, do LT and invert the result.
-        To compute NE, do EQ and invert the result.
-
-        Therefore, the code below must handle only EQ and LT.  */
-
-      if (code == LE_EXPR || code == GT_EXPR)
-       {
-         tem = arg0, arg0 = arg1, arg1 = tem;
-         code = swap_tree_comparison (code);
-       }
-
-      /* Note that it is safe to invert for real values here because we
-        will check below in the one case that it matters.  */
-
-      t1 = NULL_TREE;
-      invert = 0;
-      if (code == NE_EXPR || code == GE_EXPR)
-       {
-         invert = 1;
-         code = invert_tree_comparison (code);
-       }
-
-      /* Compute a result for LT or EQ if args permit;
-        otherwise return T.  */
-      if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+      /* We can fold X/C1 op C2 where C1 and C2 are integer constants
+        into a single range test.  */
+      if (TREE_CODE (arg0) == TRUNC_DIV_EXPR
+         && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+         && !integer_zerop (TREE_OPERAND (arg0, 1))
+         && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
+         && !TREE_OVERFLOW (arg1))
        {
-         if (code == EQ_EXPR)
-           t1 = build_int_2 (tree_int_cst_equal (arg0, arg1), 0);
-         else
-           t1 = build_int_2 ((TREE_UNSIGNED (TREE_TYPE (arg0))
-                              ? INT_CST_LT_UNSIGNED (arg0, arg1)
-                              : INT_CST_LT (arg0, arg1)),
-                             0);
-       }
-
-#if 0 /* This is no longer useful, but breaks some real code.  */
-      /* Assume a nonexplicit constant cannot equal an explicit one,
-        since such code would be undefined anyway.
-        Exception: on sysvr4, using #pragma weak,
-        a label can come out as 0.  */
-      else if (TREE_CODE (arg1) == INTEGER_CST
-              && !integer_zerop (arg1)
-              && TREE_CONSTANT (arg0)
-              && TREE_CODE (arg0) == ADDR_EXPR
-              && code == EQ_EXPR)
-       t1 = build_int_2 (0, 0);
-#endif
-      /* Two real constants can be compared explicitly.  */
-      else if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
-       {
-         /* If either operand is a NaN, the result is false with two
-            exceptions: First, an NE_EXPR is true on NaNs, but that case
-            is already handled correctly since we will be inverting the
-            result for NE_EXPR.  Second, if we had inverted a LE_EXPR
-            or a GE_EXPR into a LT_EXPR, we must return true so that it
-            will be inverted into false.  */
-
-         if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg0))
-             || REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
-           t1 = build_int_2 (invert && code == LT_EXPR, 0);
-
-         else if (code == EQ_EXPR)
-           t1 = build_int_2 (REAL_VALUES_EQUAL (TREE_REAL_CST (arg0),
-                                                TREE_REAL_CST (arg1)),
-                             0);
-         else
-           t1 = build_int_2 (REAL_VALUES_LESS (TREE_REAL_CST (arg0),
-                                               TREE_REAL_CST (arg1)),
-                             0);
+         t1 = fold_div_compare (code, type, arg0, arg1);
+         if (t1 != NULL_TREE)
+           return t1;
        }
 
-      if (t1 == NULL_TREE)
-       return t;
-
-      if (invert)
-       TREE_INT_CST_LOW (t1) ^= 1;
-
-      TREE_TYPE (t1) = type;
-      if (TREE_CODE (type) == BOOLEAN_TYPE)
-       return (*lang_hooks.truthvalue_conversion) (t1);
-      return t1;
+      /* Both ARG0 and ARG1 are known to be constants at this point.  */
+      t1 = fold_relational_const (code, type, arg0, arg1);
+      return (t1 == NULL_TREE ? t : t1);
 
     case COND_EXPR:
       /* Pedantic ANSI C says that a conditional expression is never an lvalue,
@@ -8066,11 +7995,11 @@ fold (tree expr)
             has the same type as the COND_EXPR.  This avoids optimizing
             away "c ? x : throw", where the throw has a void type.  */
          if (! VOID_TYPE_P (TREE_TYPE (tem))
-             || VOID_TYPE_P (TREE_TYPE (t)))
+             || VOID_TYPE_P (type))
            return pedantic_non_lvalue (tem);
          return t;
        }
-      if (operand_equal_p (arg1, TREE_OPERAND (expr, 2), 0))
+      if (operand_equal_p (arg1, TREE_OPERAND (t, 2), 0))
        return pedantic_omit_one_operand (type, arg1, arg0);
 
       /* If we have A op B ? A : C, we may be able to convert this to a
@@ -8122,15 +8051,15 @@ fold (tree expr)
                return pedantic_non_lvalue (fold_convert (type, arg1));
              case GE_EXPR:
              case GT_EXPR:
-               if (TREE_UNSIGNED (TREE_TYPE (arg1)))
-                 arg1 = fold_convert ((*lang_hooks.types.signed_type)
+               if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
+                 arg1 = fold_convert (lang_hooks.types.signed_type
                                       (TREE_TYPE (arg1)), arg1);
                arg1 = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
                return pedantic_non_lvalue (fold_convert (type, arg1));
              case LE_EXPR:
              case LT_EXPR:
-               if (TREE_UNSIGNED (TREE_TYPE (arg1)))
-                 arg1 = fold_convert ((lang_hooks.types.signed_type)
+               if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
+                 arg1 = fold_convert (lang_hooks.types.signed_type
                                       (TREE_TYPE (arg1)), arg1);
                arg1 = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
                arg1 = negate_expr (fold_convert (type, arg1));
@@ -8207,21 +8136,21 @@ fold (tree expr)
                     corresponding COND_EXPR.  */
                  if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
                    return pedantic_non_lvalue (fold_convert
-                     (type, fold (build (MIN_EXPR, comp_type,
-                                         (comp_code == LE_EXPR
-                                          ? comp_op0 : comp_op1),
-                                         (comp_code == LE_EXPR
-                                          ? comp_op1 : comp_op0)))));
+                     (type, fold (build2 (MIN_EXPR, comp_type,
+                                          (comp_code == LE_EXPR
+                                           ? comp_op0 : comp_op1),
+                                          (comp_code == LE_EXPR
+                                           ? comp_op1 : comp_op0)))));
                  break;
                case GE_EXPR:
                case GT_EXPR:
                  if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
                    return pedantic_non_lvalue (fold_convert
-                     (type, fold (build (MAX_EXPR, comp_type,
-                                         (comp_code == GE_EXPR
-                                          ? comp_op0 : comp_op1),
-                                         (comp_code == GE_EXPR
-                                          ? comp_op1 : comp_op0)))));
+                     (type, fold (build2 (MAX_EXPR, comp_type,
+                                          (comp_code == GE_EXPR
+                                           ? comp_op0 : comp_op1),
+                                          (comp_code == GE_EXPR
+                                           ? comp_op1 : comp_op0)))));
                  break;
                default:
                  abort ();
@@ -8242,47 +8171,55 @@ fold (tree expr)
              case EQ_EXPR:
                /* We can replace A with C1 in this case.  */
                arg1 = fold_convert (type, TREE_OPERAND (arg0, 1));
-               return fold (build (code, type, TREE_OPERAND (t, 0), arg1,
-                                   TREE_OPERAND (t, 2)));
+               return fold (build3 (code, type, TREE_OPERAND (t, 0), arg1,
+                                    TREE_OPERAND (t, 2)));
 
              case LT_EXPR:
                /* If C1 is C2 + 1, this is min(A, C2).  */
-               if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), 1)
+               if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
+                                      OEP_ONLY_CONST)
                    && operand_equal_p (TREE_OPERAND (arg0, 1),
                                        const_binop (PLUS_EXPR, arg2,
-                                                    integer_one_node, 0), 1))
+                                                    integer_one_node, 0),
+                                       OEP_ONLY_CONST))
                  return pedantic_non_lvalue
-                   (fold (build (MIN_EXPR, type, arg1, arg2)));
+                   (fold (build2 (MIN_EXPR, type, arg1, arg2)));
                break;
 
              case LE_EXPR:
                /* If C1 is C2 - 1, this is min(A, C2).  */
-               if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), 1)
+               if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
+                                      OEP_ONLY_CONST)
                    && operand_equal_p (TREE_OPERAND (arg0, 1),
                                        const_binop (MINUS_EXPR, arg2,
-                                                    integer_one_node, 0), 1))
+                                                    integer_one_node, 0),
+                                       OEP_ONLY_CONST))
                  return pedantic_non_lvalue
-                   (fold (build (MIN_EXPR, type, arg1, arg2)));
+                   (fold (build2 (MIN_EXPR, type, arg1, arg2)));
                break;
 
              case GT_EXPR:
                /* If C1 is C2 - 1, this is max(A, C2).  */
-               if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), 1)
+               if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
+                                      OEP_ONLY_CONST)
                    && operand_equal_p (TREE_OPERAND (arg0, 1),
                                        const_binop (MINUS_EXPR, arg2,
-                                                    integer_one_node, 0), 1))
+                                                    integer_one_node, 0),
+                                       OEP_ONLY_CONST))
                  return pedantic_non_lvalue
-                   (fold (build (MAX_EXPR, type, arg1, arg2)));
+                   (fold (build2 (MAX_EXPR, type, arg1, arg2)));
                break;
 
              case GE_EXPR:
                /* If C1 is C2 + 1, this is max(A, C2).  */
-               if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), 1)
+               if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
+                                      OEP_ONLY_CONST)
                    && operand_equal_p (TREE_OPERAND (arg0, 1),
                                        const_binop (PLUS_EXPR, arg2,
-                                                    integer_one_node, 0), 1))
+                                                    integer_one_node, 0),
+                                       OEP_ONLY_CONST))
                  return pedantic_non_lvalue
-                   (fold (build (MAX_EXPR, type, arg1, arg2)));
+                   (fold (build2 (MAX_EXPR, type, arg1, arg2)));
                break;
              case NE_EXPR:
                break;
@@ -8302,8 +8239,8 @@ fold (tree expr)
          tem = invert_truthvalue (arg0);
 
          if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
-           return fold (build (code, type, tem,
-                        TREE_OPERAND (t, 2), TREE_OPERAND (t, 1)));
+           return fold (build3 (code, type, tem,
+                                TREE_OPERAND (t, 2), TREE_OPERAND (t, 1)));
        }
 
       /* Convert A ? 1 : 0 to simply A.  */
@@ -8333,7 +8270,7 @@ fold (tree expr)
          && integer_pow2p (arg1)
          && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR
          && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1),
-                             arg1, 1))
+                             arg1, OEP_ONLY_CONST))
        return pedantic_non_lvalue (fold_convert (type,
                                                  TREE_OPERAND (arg0, 0)));
 
@@ -8341,8 +8278,8 @@ fold (tree expr)
       if (integer_zerop (TREE_OPERAND (t, 2))
          && truth_value_p (TREE_CODE (arg0))
          && truth_value_p (TREE_CODE (arg1)))
-       return pedantic_non_lvalue (fold (build (TRUTH_ANDIF_EXPR, type,
-                                                arg0, arg1)));
+       return pedantic_non_lvalue (fold (build2 (TRUTH_ANDIF_EXPR, type,
+                                                 arg0, arg1)));
 
       /* Convert A ? B : 1 into !A || B if A and B are truth values.  */
       if (integer_onep (TREE_OPERAND (t, 2))
@@ -8352,8 +8289,8 @@ fold (tree expr)
          /* Only perform transformation if ARG0 is easily inverted.  */
          tem = invert_truthvalue (arg0);
          if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
-           return pedantic_non_lvalue (fold (build (TRUTH_ORIF_EXPR, type,
-                                                    tem, arg1)));
+           return pedantic_non_lvalue (fold (build2 (TRUTH_ORIF_EXPR, type,
+                                                     tem, arg1)));
        }
 
       return t;
@@ -8382,11 +8319,11 @@ fold (tree expr)
       else if (TREE_CODE (arg0) == COMPLEX_CST)
        return TREE_REALPART (arg0);
       else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-       return fold (build (TREE_CODE (arg0), type,
-                           fold (build1 (REALPART_EXPR, type,
-                                         TREE_OPERAND (arg0, 0))),
-                           fold (build1 (REALPART_EXPR,
-                                         type, TREE_OPERAND (arg0, 1)))));
+       return fold (build2 (TREE_CODE (arg0), type,
+                            fold (build1 (REALPART_EXPR, type,
+                                          TREE_OPERAND (arg0, 0))),
+                            fold (build1 (REALPART_EXPR, type,
+                                          TREE_OPERAND (arg0, 1)))));
       return t;
 
     case IMAGPART_EXPR:
@@ -8398,11 +8335,11 @@ fold (tree expr)
       else if (TREE_CODE (arg0) == COMPLEX_CST)
        return TREE_IMAGPART (arg0);
       else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-       return fold (build (TREE_CODE (arg0), type,
-                           fold (build1 (IMAGPART_EXPR, type,
-                                         TREE_OPERAND (arg0, 0))),
-                           fold (build1 (IMAGPART_EXPR, type,
-                                         TREE_OPERAND (arg0, 1)))));
+       return fold (build2 (TREE_CODE (arg0), type,
+                            fold (build1 (IMAGPART_EXPR, type,
+                                          TREE_OPERAND (arg0, 0))),
+                            fold (build1 (IMAGPART_EXPR, type,
+                                          TREE_OPERAND (arg0, 1)))));
       return t;
 
       /* Pull arithmetic ops out of the CLEANUP_POINT_EXPR where
@@ -8432,15 +8369,15 @@ fold (tree expr)
            if (TREE_CONSTANT (arg00)
                || ((code0 == TRUTH_ANDIF_EXPR || code0 == TRUTH_ORIF_EXPR)
                    && ! has_cleanups (arg00)))
-             return fold (build (code0, type, arg00,
-                                 fold (build1 (CLEANUP_POINT_EXPR,
-                                               TREE_TYPE (arg01), arg01))));
+             return fold (build2 (code0, type, arg00,
+                                  fold (build1 (CLEANUP_POINT_EXPR,
+                                                TREE_TYPE (arg01), arg01))));
 
            if (TREE_CONSTANT (arg01))
-             return fold (build (code0, type,
-                                 fold (build1 (CLEANUP_POINT_EXPR,
-                                               TREE_TYPE (arg00), arg00)),
-                                 arg01));
+             return fold (build2 (code0, type,
+                                  fold (build1 (CLEANUP_POINT_EXPR,
+                                                TREE_TYPE (arg00), arg00)),
+                                  arg01));
          }
 
        return t;
@@ -8448,12 +8385,12 @@ fold (tree expr)
 
     case CALL_EXPR:
       /* Check for a built-in function.  */
-      if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR
-         && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (expr, 0), 0))
+      if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
+         && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
              == FUNCTION_DECL)
-         && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (expr, 0), 0)))
+         && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
        {
-         tree tmp = fold_builtin (expr);
+         tree tmp = fold_builtin (t);
          if (tmp)
            return tmp;
        }
@@ -8776,7 +8713,7 @@ multiple_of_p (tree type, tree top, tree bottom)
 
     case INTEGER_CST:
       if (TREE_CODE (bottom) != INTEGER_CST
-         || (TREE_UNSIGNED (type)
+         || (TYPE_UNSIGNED (type)
              && (tree_int_cst_sgn (top) < 0
                  || tree_int_cst_sgn (bottom) < 0)))
        return 0;
@@ -8817,8 +8754,8 @@ tree_expr_nonnegative_p (tree t)
        {
          tree inner1 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
          tree inner2 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0));
-         if (TREE_CODE (inner1) == INTEGER_TYPE && TREE_UNSIGNED (inner1)
-             && TREE_CODE (inner2) == INTEGER_TYPE && TREE_UNSIGNED (inner2))
+         if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1)
+             && TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2))
            {
              unsigned int prec = MAX (TYPE_PRECISION (inner1),
                                       TYPE_PRECISION (inner2)) + 1;
@@ -8845,8 +8782,8 @@ tree_expr_nonnegative_p (tree t)
        {
          tree inner1 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
          tree inner2 = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0));
-         if (TREE_CODE (inner1) == INTEGER_TYPE && TREE_UNSIGNED (inner1)
-             && TREE_CODE (inner2) == INTEGER_TYPE && TREE_UNSIGNED (inner2))
+         if (TREE_CODE (inner1) == INTEGER_TYPE && TYPE_UNSIGNED (inner1)
+             && TREE_CODE (inner2) == INTEGER_TYPE && TYPE_UNSIGNED (inner2))
            return TYPE_PRECISION (inner1) + TYPE_PRECISION (inner2)
                   < TYPE_PRECISION (TREE_TYPE (t));
        }
@@ -8869,6 +8806,14 @@ tree_expr_nonnegative_p (tree t)
       return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
             && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
 
+    case BIT_AND_EXPR:
+      return tree_expr_nonnegative_p (TREE_OPERAND (t, 1))
+            || tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
+            && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+
     case NOP_EXPR:
       {
        tree inner_type = TREE_TYPE (TREE_OPERAND (t, 0));
@@ -8880,7 +8825,7 @@ tree_expr_nonnegative_p (tree t)
              return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
            if (TREE_CODE (inner_type) == INTEGER_TYPE)
              {
-               if (TREE_UNSIGNED (inner_type))
+               if (TYPE_UNSIGNED (inner_type))
                  return 1;
                return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
              }
@@ -8891,7 +8836,7 @@ tree_expr_nonnegative_p (tree t)
              return tree_expr_nonnegative_p (TREE_OPERAND (t,0));
            if (TREE_CODE (inner_type) == INTEGER_TYPE)
              return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)
-                     && TREE_UNSIGNED (inner_type);
+                     && TYPE_UNSIGNED (inner_type);
          }
       }
       break;
@@ -8929,65 +8874,75 @@ tree_expr_nonnegative_p (tree t)
            && DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD)
          switch (DECL_FUNCTION_CODE (fndecl))
            {
-           case BUILT_IN_CABS:
-           case BUILT_IN_CABSL:
-           case BUILT_IN_CABSF:
-           case BUILT_IN_EXP:
-           case BUILT_IN_EXPF:
-           case BUILT_IN_EXPL:
-           case BUILT_IN_EXP2:
-           case BUILT_IN_EXP2F:
-           case BUILT_IN_EXP2L:
-           case BUILT_IN_EXP10:
-           case BUILT_IN_EXP10F:
-           case BUILT_IN_EXP10L:
-           case BUILT_IN_FABS:
-           case BUILT_IN_FABSF:
-           case BUILT_IN_FABSL:
-           case BUILT_IN_FFS:
-           case BUILT_IN_FFSL:
-           case BUILT_IN_FFSLL:
-           case BUILT_IN_PARITY:
-           case BUILT_IN_PARITYL:
-           case BUILT_IN_PARITYLL:
-           case BUILT_IN_POPCOUNT:
-           case BUILT_IN_POPCOUNTL:
-           case BUILT_IN_POPCOUNTLL:
-           case BUILT_IN_POW10:
-           case BUILT_IN_POW10F:
-           case BUILT_IN_POW10L:
-           case BUILT_IN_SQRT:
-           case BUILT_IN_SQRTF:
-           case BUILT_IN_SQRTL:
+#define CASE_BUILTIN_F(BUILT_IN_FN) \
+  case BUILT_IN_FN: case BUILT_IN_FN##F: case BUILT_IN_FN##L:
+#define CASE_BUILTIN_I(BUILT_IN_FN) \
+  case BUILT_IN_FN: case BUILT_IN_FN##L: case BUILT_IN_FN##LL:
+
+           CASE_BUILTIN_F (BUILT_IN_ACOS)
+           CASE_BUILTIN_F (BUILT_IN_ACOSH)
+           CASE_BUILTIN_F (BUILT_IN_CABS)
+           CASE_BUILTIN_F (BUILT_IN_COSH)
+           CASE_BUILTIN_F (BUILT_IN_ERFC)
+           CASE_BUILTIN_F (BUILT_IN_EXP)
+           CASE_BUILTIN_F (BUILT_IN_EXP10)
+           CASE_BUILTIN_F (BUILT_IN_EXP2)
+           CASE_BUILTIN_F (BUILT_IN_FABS)
+           CASE_BUILTIN_F (BUILT_IN_FDIM)
+           CASE_BUILTIN_F (BUILT_IN_FREXP)
+           CASE_BUILTIN_F (BUILT_IN_HYPOT)
+           CASE_BUILTIN_F (BUILT_IN_POW10)
+           CASE_BUILTIN_F (BUILT_IN_SQRT)
+           CASE_BUILTIN_I (BUILT_IN_FFS)
+           CASE_BUILTIN_I (BUILT_IN_PARITY)
+           CASE_BUILTIN_I (BUILT_IN_POPCOUNT)
+             /* Always true.  */
              return 1;
 
-           case BUILT_IN_ATAN:
-           case BUILT_IN_ATANF:
-           case BUILT_IN_ATANL:
-           case BUILT_IN_CEIL:
-           case BUILT_IN_CEILF:
-           case BUILT_IN_CEILL:
-           case BUILT_IN_FLOOR:
-           case BUILT_IN_FLOORF:
-           case BUILT_IN_FLOORL:
-           case BUILT_IN_NEARBYINT:
-           case BUILT_IN_NEARBYINTF:
-           case BUILT_IN_NEARBYINTL:
-           case BUILT_IN_ROUND:
-           case BUILT_IN_ROUNDF:
-           case BUILT_IN_ROUNDL:
-           case BUILT_IN_TRUNC:
-           case BUILT_IN_TRUNCF:
-           case BUILT_IN_TRUNCL:
+           CASE_BUILTIN_F (BUILT_IN_ASINH)
+           CASE_BUILTIN_F (BUILT_IN_ATAN)
+           CASE_BUILTIN_F (BUILT_IN_ATANH)
+           CASE_BUILTIN_F (BUILT_IN_CBRT)
+           CASE_BUILTIN_F (BUILT_IN_CEIL)
+           CASE_BUILTIN_F (BUILT_IN_ERF)
+           CASE_BUILTIN_F (BUILT_IN_EXPM1)
+           CASE_BUILTIN_F (BUILT_IN_FLOOR)
+           CASE_BUILTIN_F (BUILT_IN_FMOD)
+           CASE_BUILTIN_F (BUILT_IN_LDEXP)
+           CASE_BUILTIN_F (BUILT_IN_LLRINT)
+           CASE_BUILTIN_F (BUILT_IN_LLROUND)
+           CASE_BUILTIN_F (BUILT_IN_LRINT)
+           CASE_BUILTIN_F (BUILT_IN_LROUND)
+           CASE_BUILTIN_F (BUILT_IN_MODF)
+           CASE_BUILTIN_F (BUILT_IN_NEARBYINT)
+           CASE_BUILTIN_F (BUILT_IN_POW)
+           CASE_BUILTIN_F (BUILT_IN_RINT)
+           CASE_BUILTIN_F (BUILT_IN_ROUND)
+           CASE_BUILTIN_F (BUILT_IN_SIGNBIT)
+           CASE_BUILTIN_F (BUILT_IN_SINH)
+           CASE_BUILTIN_F (BUILT_IN_TANH)
+           CASE_BUILTIN_F (BUILT_IN_TRUNC)
+             /* True if the 1st argument is nonnegative.  */
              return tree_expr_nonnegative_p (TREE_VALUE (arglist));
 
-           case BUILT_IN_POW:
-           case BUILT_IN_POWF:
-           case BUILT_IN_POWL:
-             return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+           CASE_BUILTIN_F(BUILT_IN_FMAX)
+             /* True if the 1st OR 2nd arguments are nonnegative.  */
+             return tree_expr_nonnegative_p (TREE_VALUE (arglist))
+               || tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
+
+           CASE_BUILTIN_F(BUILT_IN_FMIN)
+             /* True if the 1st AND 2nd arguments are nonnegative.  */
+             return tree_expr_nonnegative_p (TREE_VALUE (arglist))
+               && tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
+
+           CASE_BUILTIN_F(BUILT_IN_COPYSIGN)
+             /* True if the 2nd argument is nonnegative.  */
+             return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
 
            default:
              break;
+#undef CASE_BUILTIN_F
+#undef CASE_BUILTIN_I
            }
       }
 
@@ -9003,6 +8958,110 @@ tree_expr_nonnegative_p (tree t)
   return 0;
 }
 
+/* Return true when T is an address and is known to be nonzero.
+   For floating point we further ensure that T is not denormal.
+   Similar logic is present in nonzero_address in rtlanal.h  */
+
+static bool
+tree_expr_nonzero_p (tree t)
+{
+  tree type = TREE_TYPE (t);
+
+  /* Doing something useful for floating point would need more work.  */
+  if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
+    return false;
+
+  switch (TREE_CODE (t))
+    {
+    case ABS_EXPR:
+      if (!TYPE_UNSIGNED (type) && !flag_wrapv)
+       return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+
+    case INTEGER_CST:
+      return !integer_zerop (t);
+
+    case PLUS_EXPR:
+      if (!TYPE_UNSIGNED (type) && !flag_wrapv)
+       {
+         /* With the presence of negative values it is hard
+            to say something.  */
+         if (!tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
+             || !tree_expr_nonnegative_p (TREE_OPERAND (t, 1)))
+           return false;
+         /* One of operands must be positive and the other non-negative.  */
+         return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
+                 || tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
+       }
+      break;
+
+    case MULT_EXPR:
+      if (!TYPE_UNSIGNED (type) && !flag_wrapv)
+       {
+         return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
+                 && tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
+       }
+      break;
+
+    case NOP_EXPR:
+      {
+       tree inner_type = TREE_TYPE (TREE_OPERAND (t, 0));
+       tree outer_type = TREE_TYPE (t);
+
+       return (TYPE_PRECISION (inner_type) >= TYPE_PRECISION (outer_type)
+               && tree_expr_nonzero_p (TREE_OPERAND (t, 0)));
+      }
+      break;
+
+   case ADDR_EXPR:
+      /* Weak declarations may link to NULL.  */
+      if (DECL_P (TREE_OPERAND (t, 0)))
+       return !DECL_WEAK (TREE_OPERAND (t, 0));
+      /* Constants and all other cases are never weak.  */
+      return true;
+
+    case COND_EXPR:
+      return (tree_expr_nonzero_p (TREE_OPERAND (t, 1))
+             && tree_expr_nonzero_p (TREE_OPERAND (t, 2)));
+
+    case MIN_EXPR:
+      return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
+             && tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
+
+    case MAX_EXPR:
+      if (tree_expr_nonzero_p (TREE_OPERAND (t, 0)))
+       {
+         /* When both operands are nonzero, then MAX must be too.  */
+         if (tree_expr_nonzero_p (TREE_OPERAND (t, 1)))
+           return true;
+
+         /* MAX where operand 0 is positive is positive.  */
+         return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+       }
+      /* MAX where operand 1 is positive is positive.  */
+      else if (tree_expr_nonzero_p (TREE_OPERAND (t, 1))
+              && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)))
+       return true;
+      break;
+
+    case COMPOUND_EXPR:
+    case MODIFY_EXPR:
+    case BIND_EXPR:
+      return tree_expr_nonzero_p (TREE_OPERAND (t, 1));
+
+    case SAVE_EXPR:
+    case NON_LVALUE_EXPR:
+      return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+
+    case BIT_IOR_EXPR:
+      return tree_expr_nonzero_p (TREE_OPERAND (t, 1))
+            || tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+
+    default:
+      break;
+    }
+  return false;
+}
+
 /* Return true if `r' is known to be non-negative.
    Only handles constants at the moment.  */
 
@@ -9046,4 +9105,776 @@ rtl_expr_nonnegative_p (rtx r)
     }
 }
 
+
+/* See if we are applying CODE, a relational to the highest or lowest
+   possible integer of TYPE.  If so, then the result is a compile
+   time constant.  */
+
+static tree
+fold_relational_hi_lo (enum tree_code *code_p, const tree type, tree *op0_p,
+                      tree *op1_p)
+{
+  tree op0 = *op0_p;
+  tree op1 = *op1_p;
+  enum tree_code code = *code_p;
+  int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (op1)));
+
+  if (TREE_CODE (op1) == INTEGER_CST
+      && ! TREE_CONSTANT_OVERFLOW (op1)
+      && width <= HOST_BITS_PER_WIDE_INT
+      && (INTEGRAL_TYPE_P (TREE_TYPE (op1))
+         || POINTER_TYPE_P (TREE_TYPE (op1))))
+    {
+      unsigned HOST_WIDE_INT signed_max;
+      unsigned HOST_WIDE_INT max, min;
+
+      signed_max = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1;
+
+      if (TYPE_UNSIGNED (TREE_TYPE (op1)))
+        {
+          max = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
+         min = 0;
+       }
+      else
+        {
+          max = signed_max;
+         min = ((unsigned HOST_WIDE_INT) -1 << (width - 1));
+       }
+
+      if (TREE_INT_CST_HIGH (op1) == 0
+         && TREE_INT_CST_LOW (op1) == max)
+       switch (code)
+         {
+         case GT_EXPR:
+           return omit_one_operand (type,
+                                    fold_convert (type, integer_zero_node),
+                                    op0);
+         case GE_EXPR:
+           *code_p = EQ_EXPR;
+           break;
+         case LE_EXPR:
+           return omit_one_operand (type,
+                                    fold_convert (type, integer_one_node),
+                                    op0);
+         case LT_EXPR:
+           *code_p = NE_EXPR;
+           break;
+
+         /* The GE_EXPR and LT_EXPR cases above are not normally
+            reached because of  previous transformations.  */
+
+         default:
+           break;
+         }
+      else if (TREE_INT_CST_HIGH (op1) == 0
+              && TREE_INT_CST_LOW (op1) == max - 1)
+       switch (code)
+         {
+         case GT_EXPR:
+           *code_p = EQ_EXPR;
+           *op1_p = const_binop (PLUS_EXPR, op1, integer_one_node, 0);
+           break;
+         case LE_EXPR:
+           *code_p = NE_EXPR;
+           *op1_p = const_binop (PLUS_EXPR, op1, integer_one_node, 0);
+           break;
+         default:
+           break;
+         }
+      else if (TREE_INT_CST_HIGH (op1) == (min ? -1 : 0)
+              && TREE_INT_CST_LOW (op1) == min)
+       switch (code)
+         {
+         case LT_EXPR:
+           return omit_one_operand (type,
+                                    fold_convert (type, integer_zero_node),
+                                    op0);
+         case LE_EXPR:
+           *code_p = EQ_EXPR;
+           break;
+
+         case GE_EXPR:
+           return omit_one_operand (type,
+                                    fold_convert (type, integer_one_node),
+                                    op0);
+         case GT_EXPR:
+           *code_p = NE_EXPR;
+           break;
+
+         default:
+           break;
+         }
+      else if (TREE_INT_CST_HIGH (op1) == (min ? -1 : 0)
+              && TREE_INT_CST_LOW (op1) == min + 1)
+       switch (code)
+         {
+         case GE_EXPR:
+           *code_p = NE_EXPR;
+           *op1_p = const_binop (MINUS_EXPR, op1, integer_one_node, 0);
+           break;
+         case LT_EXPR:
+           *code_p = EQ_EXPR;
+           *op1_p = const_binop (MINUS_EXPR, op1, integer_one_node, 0);
+           break;
+         default:
+           break;
+         }
+
+      else if (TREE_INT_CST_HIGH (op1) == 0
+              && TREE_INT_CST_LOW (op1) == signed_max
+              && TYPE_UNSIGNED (TREE_TYPE (op1))
+              /* signed_type does not work on pointer types.  */
+              && INTEGRAL_TYPE_P (TREE_TYPE (op1)))
+       {
+         /* The following case also applies to X < signed_max+1
+            and X >= signed_max+1 because previous transformations.  */
+         if (code == LE_EXPR || code == GT_EXPR)
+           {
+             tree st0, st1, exp, retval;
+             st0 = lang_hooks.types.signed_type (TREE_TYPE (op0));
+             st1 = lang_hooks.types.signed_type (TREE_TYPE (op1));
+
+             exp = build2 (code == LE_EXPR ? GE_EXPR: LT_EXPR,
+                           type,
+                           fold_convert (st0, op0),
+                           fold_convert (st1, integer_zero_node));
+
+             retval
+               = nondestructive_fold_binary_to_constant (TREE_CODE (exp),
+                                                         TREE_TYPE (exp),
+                                                         TREE_OPERAND (exp, 0),
+                                                         TREE_OPERAND (exp, 1));
+
+             /* If we are in gimple form, then returning EXP would create
+                non-gimple expressions.  Clearing it is safe and insures
+                we do not allow a non-gimple expression to escape.  */
+             if (in_gimple_form)
+               exp = NULL;
+
+             return (retval ? retval : exp);
+           }
+       }
+    }
+
+  return NULL_TREE;
+}
+
+
+/* Given the components of a binary expression CODE, TYPE, OP0 and OP1,
+   attempt to fold the expression to a constant without modifying TYPE,
+   OP0 or OP1.
+
+   If the expression could be simplified to a constant, then return
+   the constant.  If the expression would not be simplified to a
+   constant, then return NULL_TREE.
+
+   Note this is primarily designed to be called after gimplification
+   of the tree structures and when at least one operand is a constant.
+   As a result of those simplifying assumptions this routine is far
+   simpler than the generic fold routine.  */
+
+tree
+nondestructive_fold_binary_to_constant (enum tree_code code, tree type,
+                                       tree op0, tree op1)
+{
+  int wins = 1;
+  tree subop0;
+  tree subop1;
+  tree tem;
+
+  /* If this is a commutative operation, and ARG0 is a constant, move it
+     to ARG1 to reduce the number of tests below.  */
+  if (commutative_tree_code (code)
+      && (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST))
+    {
+      tem = op0;
+      op0 = op1;
+      op1 = tem;
+    }
+
+  /* If either operand is a complex type, extract its real component.  */
+  if (TREE_CODE (op0) == COMPLEX_CST)
+    subop0 = TREE_REALPART (op0);
+  else
+    subop0 = op0;
+
+  if (TREE_CODE (op1) == COMPLEX_CST)
+    subop1 = TREE_REALPART (op1);
+  else
+    subop1 = op1;
+
+  /* Note if either argument is not a real or integer constant.
+     With a few exceptions, simplification is limited to cases
+     where both arguments are constants.  */
+  if ((TREE_CODE (subop0) != INTEGER_CST
+       && TREE_CODE (subop0) != REAL_CST)
+      || (TREE_CODE (subop1) != INTEGER_CST
+         && TREE_CODE (subop1) != REAL_CST))
+    wins = 0;
+
+  switch (code)
+    {
+    case PLUS_EXPR:
+      /* (plus (address) (const_int)) is a constant.  */
+      if (TREE_CODE (op0) == PLUS_EXPR
+         && TREE_CODE (op1) == INTEGER_CST
+         && (TREE_CODE (TREE_OPERAND (op0, 0)) == ADDR_EXPR
+             || (TREE_CODE (TREE_OPERAND (op0, 0)) == NOP_EXPR
+                 && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (op0, 0), 0))
+                     == ADDR_EXPR)))
+         && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST)
+       {
+          return build2 (PLUS_EXPR, type, TREE_OPERAND (op0, 0),
+                        const_binop (PLUS_EXPR, op1,
+                                     TREE_OPERAND (op0, 1), 0));
+       }
+    case BIT_XOR_EXPR:
+
+    binary:
+      if (!wins)
+       return NULL_TREE;
+
+      /* Both arguments are constants.  Simplify.  */
+      tem = const_binop (code, op0, op1, 0);
+      if (tem != NULL_TREE)
+       {
+         /* The return value should always have the same type as
+            the original expression.  */
+         if (TREE_TYPE (tem) != type)
+           tem = fold_convert (type, tem);
+
+         return tem;
+       }
+      return NULL_TREE;
+      
+    case MINUS_EXPR:
+      /* Fold &x - &x.  This can happen from &x.foo - &x.
+         This is unsafe for certain floats even in non-IEEE formats.
+         In IEEE, it is unsafe because it does wrong for NaNs.
+         Also note that operand_equal_p is always false if an
+         operand is volatile.  */
+      if (! FLOAT_TYPE_P (type) && operand_equal_p (op0, op1, 0))
+       return fold_convert (type, integer_zero_node);
+
+      goto binary;
+
+    case MULT_EXPR:
+    case BIT_AND_EXPR:
+      /* Special case multiplication or bitwise AND where one argument
+        is zero.  */
+      if (! FLOAT_TYPE_P (type) && integer_zerop (op1))
+       return omit_one_operand (type, op1, op0);
+      else
+        if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (op0)))
+           && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op0)))
+           && real_zerop (op1))
+         return omit_one_operand (type, op1, op0);
+
+      goto binary;
+
+    case BIT_IOR_EXPR:
+      /* Special case when we know the result will be all ones.  */
+      if (integer_all_onesp (op1))
+       return omit_one_operand (type, op1, op0);
+
+      goto binary;
+       
+    case TRUNC_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case RDIV_EXPR:
+      /* Division by zero is undefined.  */
+      if (integer_zerop (op1))
+       return NULL_TREE;
+
+      if (TREE_CODE (op1) == REAL_CST
+         && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (op1)))
+         && real_zerop (op1))
+       return NULL_TREE;
+
+      goto binary;
+
+    case MIN_EXPR:
+      if (INTEGRAL_TYPE_P (type)
+         && operand_equal_p (op1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST))
+       return omit_one_operand (type, op1, op0);
+
+      goto binary;
+
+    case MAX_EXPR:
+      if (INTEGRAL_TYPE_P (type)
+         && TYPE_MAX_VALUE (type)
+         && operand_equal_p (op1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST))
+       return omit_one_operand (type, op1, op0);
+
+      goto binary;
+
+    case RSHIFT_EXPR:
+      /* Optimize -1 >> x for arithmetic right shifts.  */
+      if (integer_all_onesp (op0) && ! TYPE_UNSIGNED (type))
+       return omit_one_operand (type, op0, op1);
+      /* ... fall through ...  */
+
+    case LSHIFT_EXPR:
+      if (integer_zerop (op0))
+       return omit_one_operand (type, op0, op1);
+
+      /* Since negative shift count is not well-defined, don't
+        try to compute it in the compiler.  */
+      if (TREE_CODE (op1) == INTEGER_CST && tree_int_cst_sgn (op1) < 0)
+       return NULL_TREE;
+
+      goto binary;
+
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      /* -1 rotated either direction by any amount is still -1.  */
+      if (integer_all_onesp (op0))
+       return omit_one_operand (type, op0, op1);
+
+      /* 0 rotated either direction by any amount is still zero.  */
+      if (integer_zerop (op0))
+       return omit_one_operand (type, op0, op1);
+
+      goto binary;
+
+    case COMPLEX_EXPR:
+      if (wins)
+       return build_complex (type, op0, op1);
+      return NULL_TREE;
+
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+      /* If one arg is a real or integer constant, put it last.  */
+      if ((TREE_CODE (op0) == INTEGER_CST
+          && TREE_CODE (op1) != INTEGER_CST)
+         || (TREE_CODE (op0) == REAL_CST
+             && TREE_CODE (op0) != REAL_CST))
+       {
+         tree temp;
+
+         temp = op0;
+         op0 = op1;
+         op1 = temp;
+         code = swap_tree_comparison (code);
+       }
+
+      /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
+        This transformation affects the cases which are handled in later
+        optimizations involving comparisons with non-negative constants.  */
+      if (TREE_CODE (op1) == INTEGER_CST
+         && TREE_CODE (op0) != INTEGER_CST
+         && tree_int_cst_sgn (op1) > 0)
+       {
+         switch (code)
+           {
+           case GE_EXPR:
+             code = GT_EXPR;
+             op1 = const_binop (MINUS_EXPR, op1, integer_one_node, 0);
+             break;
+
+           case LT_EXPR:
+             code = LE_EXPR;
+             op1 = const_binop (MINUS_EXPR, op1, integer_one_node, 0);
+             break;
+
+           default:
+             break;
+           }
+       }
+
+      tem = fold_relational_hi_lo (&code, type, &op0, &op1);
+      if (tem)
+       return tem;
+
+      if (!wins)
+       return NULL_TREE;
+
+      return fold_relational_const (code, type, op0, op1);
+
+    case RANGE_EXPR:
+      /* This could probably be handled.  */
+      return NULL_TREE;
+
+    case TRUTH_AND_EXPR:
+      /* If second arg is constant zero, result is zero, but first arg
+        must be evaluated.  */
+      if (integer_zerop (op1))
+       return omit_one_operand (type, op1, op0);
+      /* Likewise for first arg, but note that only the TRUTH_AND_EXPR
+        case will be handled here.  */
+      if (integer_zerop (op0))
+       return omit_one_operand (type, op0, op1);
+      if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST)
+       {
+         int x1 = ! integer_zerop (op0);
+         int x2 = ! integer_zerop (op1);
+
+         return ((x1 & x2) ? integer_one_node : integer_zero_node);
+       }
+      return NULL_TREE;
+
+    case TRUTH_OR_EXPR:
+      /* If second arg is constant true, result is true, but we must
+        evaluate first arg.  */
+      if (TREE_CODE (op1) == INTEGER_CST && ! integer_zerop (op1))
+       return omit_one_operand (type, op1, op0);
+      /* Likewise for first arg, but note this only occurs here for
+        TRUTH_OR_EXPR.  */
+      if (TREE_CODE (op0) == INTEGER_CST && ! integer_zerop (op0))
+       return omit_one_operand (type, op0, op1);
+      if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST)
+       {
+         int x1 = ! integer_zerop (op0);
+         int x2 = ! integer_zerop (op1);
+
+         return ((x1 | x2) ? integer_one_node : integer_zero_node);
+       }
+      return NULL_TREE;
+
+    case TRUTH_XOR_EXPR:
+      if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST)
+       {
+         int x1 = ! integer_zerop (op0);
+         int x2 = ! integer_zerop (op1);
+
+         return ((x1 ^ x2) ? integer_one_node : integer_zero_node);
+       }
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Given the components of a unary expression CODE, TYPE and OP0,
+   attempt to fold the expression to a constant without modifying
+   TYPE or OP0. 
+
+   If the expression could be simplified to a constant, then return
+   the constant.  If the expression would not be simplified to a
+   constant, then return NULL_TREE.
+
+   Note this is primarily designed to be called after gimplification
+   of the tree structures and when op0 is a constant.  As a result
+   of those simplifying assumptions this routine is far simpler than
+   the generic fold routine.  */
+
+tree
+nondestructive_fold_unary_to_constant (enum tree_code code, tree type,
+                                      tree op0)
+{
+  tree t;
+
+  /* Make sure we have a suitable constant argument.  */
+  if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
+    {
+      tree subop;
+
+      if (TREE_CODE (op0) == COMPLEX_CST)
+       subop = TREE_REALPART (op0);
+      else
+       subop = op0;
+
+      if (TREE_CODE (subop) != INTEGER_CST && TREE_CODE (subop) != REAL_CST)
+       return NULL_TREE;
+    }
+
+  switch (code)
+    {
+    case NOP_EXPR:
+    case FLOAT_EXPR:
+    case CONVERT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FIX_FLOOR_EXPR:
+    case FIX_CEIL_EXPR:
+      return fold_convert_const (code, type, op0);
+
+    case NEGATE_EXPR:
+      if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)
+       return fold_negate_const (op0, type);
+      else
+       return NULL_TREE;
+
+    case ABS_EXPR:
+      if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)
+       return fold_abs_const (op0, type);
+      else
+       return NULL_TREE;
+
+    case BIT_NOT_EXPR:
+      if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)
+       {
+         t = build_int_2 (~ TREE_INT_CST_LOW (op0), ~ TREE_INT_CST_HIGH (op0));
+         TREE_TYPE (t) = type;
+         force_fit_type (t, 0);
+         TREE_OVERFLOW (t) = TREE_OVERFLOW (op0);
+         TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (op0);
+         return t;
+       }
+      else
+       return NULL_TREE;
+
+    case REALPART_EXPR:
+      if (TREE_CODE (op0) == COMPLEX_CST)
+       return TREE_REALPART (op0);
+      else
+       return NULL_TREE;
+
+    case IMAGPART_EXPR:
+      if (TREE_CODE (op0) == COMPLEX_CST)
+       return TREE_IMAGPART (op0);
+      else
+       return NULL_TREE;
+
+    case CONJ_EXPR:
+      if (TREE_CODE (op0) == COMPLEX_CST
+         && TREE_CODE (TREE_TYPE (op0)) == COMPLEX_TYPE)
+       return build_complex (type, TREE_REALPART (op0),
+                             negate_expr (TREE_IMAGPART (op0)));
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* If EXP represents referencing an element in a constant string
+   (either via pointer arithmetic or array indexing), return the
+   tree representing the value accessed, otherwise return NULL.  */
+
+tree
+fold_read_from_constant_string (tree exp)
+{
+  if (TREE_CODE (exp) == INDIRECT_REF || TREE_CODE (exp) == ARRAY_REF)
+    {
+      tree exp1 = TREE_OPERAND (exp, 0);
+      tree index;
+      tree string;
+
+      if (TREE_CODE (exp) == INDIRECT_REF)
+       {
+         string = string_constant (exp1, &index);
+       }
+      else
+       {
+         tree domain = TYPE_DOMAIN (TREE_TYPE (exp1));
+         tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+         index = fold_convert (sizetype, TREE_OPERAND (exp, 1));
+         
+         /* Optimize the special-case of a zero lower bound.
+
+            We convert the low_bound to sizetype to avoid some problems
+            with constant folding.  (E.g. suppose the lower bound is 1,
+            and its mode is QI.  Without the conversion,l (ARRAY
+            +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
+            +INDEX), which becomes (ARRAY+255+INDEX).  Opps!)  */
+         if (! integer_zerop (low_bound))
+           index = size_diffop (index, fold_convert (sizetype, low_bound));
+
+         string = exp1;
+       }
+
+      if (string
+         && TREE_CODE (string) == STRING_CST
+         && TREE_CODE (index) == INTEGER_CST
+         && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
+         && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (string))))
+             == MODE_INT)
+         && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) == 1))
+       return build_int_2 ((TREE_STRING_POINTER (string)
+                            [TREE_INT_CST_LOW (index)]), 0);
+    }
+  return NULL;
+}
+
+/* Return the tree for neg (ARG0) when ARG0 is known to be either
+   an integer constant or real constant.
+
+   TYPE is the type of the result.  */
+
+static tree
+fold_negate_const (tree arg0, tree type)
+{
+  tree t = NULL_TREE;
+
+  if (TREE_CODE (arg0) == INTEGER_CST)
+    {
+      unsigned HOST_WIDE_INT low;
+      HOST_WIDE_INT high;
+      int overflow = neg_double (TREE_INT_CST_LOW (arg0),
+                                TREE_INT_CST_HIGH (arg0),
+                                &low, &high);
+      t = build_int_2 (low, high);
+      TREE_TYPE (t) = type;
+      TREE_OVERFLOW (t)
+       = (TREE_OVERFLOW (arg0)
+          | force_fit_type (t, overflow && !TYPE_UNSIGNED (type)));
+      TREE_CONSTANT_OVERFLOW (t)
+       = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
+    }
+  else if (TREE_CODE (arg0) == REAL_CST)
+    t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
+#ifdef ENABLE_CHECKING
+  else
+    abort ();
+#endif
+    
+  return t;
+}
+
+/* Return the tree for abs (ARG0) when ARG0 is known to be either
+   an integer constant or real constant.
+
+   TYPE is the type of the result.  */
+
+static tree
+fold_abs_const (tree arg0, tree type)
+{
+  tree t = NULL_TREE;
+
+  if (TREE_CODE (arg0) == INTEGER_CST)
+    {
+      /* If the value is unsigned, then the absolute value is
+        the same as the ordinary value.  */
+      if (TYPE_UNSIGNED (type))
+       return arg0;
+      /* Similarly, if the value is non-negative.  */
+      else if (INT_CST_LT (integer_minus_one_node, arg0))
+       return arg0;
+      /* If the value is negative, then the absolute value is
+        its negation.  */
+      else
+       {
+         unsigned HOST_WIDE_INT low;
+         HOST_WIDE_INT high;
+         int overflow = neg_double (TREE_INT_CST_LOW (arg0),
+                                    TREE_INT_CST_HIGH (arg0),
+                                    &low, &high);
+         t = build_int_2 (low, high);
+         TREE_TYPE (t) = type;
+         TREE_OVERFLOW (t)
+           = (TREE_OVERFLOW (arg0)
+              | force_fit_type (t, overflow));
+         TREE_CONSTANT_OVERFLOW (t)
+           = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
+         return t;
+       }
+    }
+  else if (TREE_CODE (arg0) == REAL_CST)
+    {
+      if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0)))
+       return build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
+      else
+       return arg0;
+    }
+#ifdef ENABLE_CHECKING
+  else
+    abort ();
+#endif
+    
+  return t;
+}
+
+/* Given CODE, a relational operator, the target type, TYPE and two
+   constant operands OP0 and OP1, return the result of the
+   relational operation.  If the result is not a compile time
+   constant, then return NULL_TREE.  */
+
+static tree
+fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
+{
+  tree tem;
+  int invert;
+
+  /* From here on, the only cases we handle are when the result is
+     known to be a constant.
+
+     To compute GT, swap the arguments and do LT.
+     To compute GE, do LT and invert the result.
+     To compute LE, swap the arguments, do LT and invert the result.
+     To compute NE, do EQ and invert the result.
+
+     Therefore, the code below must handle only EQ and LT.  */
+
+  if (code == LE_EXPR || code == GT_EXPR)
+    {
+      tem = op0, op0 = op1, op1 = tem;
+      code = swap_tree_comparison (code);
+    }
+
+  /* Note that it is safe to invert for real values here because we
+     will check below in the one case that it matters.  */
+
+  tem = NULL_TREE;
+  invert = 0;
+  if (code == NE_EXPR || code == GE_EXPR)
+    {
+      invert = 1;
+      code = invert_tree_comparison (code);
+    }
+
+  /* Compute a result for LT or EQ if args permit;
+     Otherwise return T.  */
+  if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST)
+    {
+      if (code == EQ_EXPR)
+        tem = build_int_2 (tree_int_cst_equal (op0, op1), 0);
+      else
+        tem = build_int_2 ((TYPE_UNSIGNED (TREE_TYPE (op0))
+                           ? INT_CST_LT_UNSIGNED (op0, op1)
+                           : INT_CST_LT (op0, op1)),
+                          0);
+    }
+
+  else if (code == EQ_EXPR && !TREE_SIDE_EFFECTS (op0)
+           && integer_zerop (op1) && tree_expr_nonzero_p (op0))
+    tem = build_int_2 (0, 0);
+
+  /* Two real constants can be compared explicitly.  */
+  else if (TREE_CODE (op0) == REAL_CST && TREE_CODE (op1) == REAL_CST)
+    {
+      /* If either operand is a NaN, the result is false with two
+        exceptions: First, an NE_EXPR is true on NaNs, but that case
+        is already handled correctly since we will be inverting the
+        result for NE_EXPR.  Second, if we had inverted a LE_EXPR
+        or a GE_EXPR into a LT_EXPR, we must return true so that it
+        will be inverted into false.  */
+
+      if (REAL_VALUE_ISNAN (TREE_REAL_CST (op0))
+          || REAL_VALUE_ISNAN (TREE_REAL_CST (op1)))
+        tem = build_int_2 (invert && code == LT_EXPR, 0);
+
+      else if (code == EQ_EXPR)
+        tem = build_int_2 (REAL_VALUES_EQUAL (TREE_REAL_CST (op0),
+                                             TREE_REAL_CST (op1)),
+                          0);
+      else
+        tem = build_int_2 (REAL_VALUES_LESS (TREE_REAL_CST (op0),
+                                            TREE_REAL_CST (op1)),
+                          0);
+    }
+
+  if (tem == NULL_TREE)
+    return NULL_TREE;
+
+  if (invert)
+    TREE_INT_CST_LOW (tem) ^= 1;
+
+  TREE_TYPE (tem) = type;
+  if (TREE_CODE (type) == BOOLEAN_TYPE)
+    return lang_hooks.truthvalue_conversion (tem);
+  return tem;
+}
+
 #include "gt-fold-const.h"