OSDN Git Service

libcpp/ChangeLog:
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index e2a1ffb..1cc2b81 100644 (file)
@@ -58,6 +58,28 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "langhooks.h"
 #include "md5.h"
 
+/* 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.  */
+enum comparison_code {
+  COMPCODE_FALSE = 0,
+  COMPCODE_LT = 1,
+  COMPCODE_EQ = 2,
+  COMPCODE_LE = 3,
+  COMPCODE_GT = 4,
+  COMPCODE_LTGT = 5,
+  COMPCODE_GE = 6,
+  COMPCODE_ORD = 7,
+  COMPCODE_UNORD = 8,
+  COMPCODE_UNLT = 9,
+  COMPCODE_UNEQ = 10,
+  COMPCODE_UNLE = 11,
+  COMPCODE_UNGT = 12,
+  COMPCODE_NE = 13,
+  COMPCODE_UNGE = 14,
+  COMPCODE_TRUE = 15
+};
+
 static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
 static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
 static bool negate_mathfn_p (enum built_in_function);
@@ -65,15 +87,16 @@ 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 enum tree_code invert_tree_comparison (enum tree_code);
+static enum tree_code invert_tree_comparison (enum tree_code, bool);
 static enum tree_code swap_tree_comparison (enum tree_code);
-static int comparison_to_compcode (enum tree_code);
-static enum tree_code compcode_to_comparison (int);
+static enum comparison_code comparison_to_compcode (enum tree_code);
+static enum tree_code compcode_to_comparison (enum comparison_code);
+static tree combine_comparisons (enum tree_code, enum tree_code,
+                                enum tree_code, tree, tree, tree);
 static int truth_value_p (enum tree_code);
 static int operand_equal_for_comparison_p (tree, tree, tree);
 static int twoval_comparison_p (tree, tree *, tree *, int *);
@@ -99,34 +122,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_not_const (tree, tree);
 static tree fold_relational_const (enum tree_code, 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.  */
-#define COMPCODE_FALSE   0
-#define COMPCODE_LT      1
-#define COMPCODE_EQ      2
-#define COMPCODE_LE      3
-#define COMPCODE_GT      4
-#define COMPCODE_NE      5
-#define COMPCODE_GE      6
-#define COMPCODE_TRUE    7
+static tree fold_relational_hi_lo (enum tree_code *, const tree,
+                                   tree *, tree *);
 
 /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
    overflow.  Suppose A, B and SUM have the same respective signs as A1, B1,
@@ -996,16 +1008,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;
 
@@ -1014,9 +1031,9 @@ 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:
@@ -1031,15 +1048,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;
 
@@ -1210,18 +1227,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
@@ -1229,7 +1246,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;
@@ -1663,7 +1680,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,
@@ -1788,6 +1805,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 ();
            }
@@ -1891,7 +1912,8 @@ fold_convert (tree type, tree arg)
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig))
     return fold (build1 (NOP_EXPR, type, arg));
 
-  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
+  if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)
+      || TREE_CODE (type) == OFFSET_TYPE)
     {
       if (TREE_CODE (arg) == INTEGER_CST)
        {
@@ -1899,7 +1921,8 @@ fold_convert (tree type, tree arg)
          if (tem != NULL_TREE)
            return tem;
        }
-      if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig))
+      if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig)
+         || TREE_CODE (orig) == OFFSET_TYPE)
         return fold (build1 (NOP_EXPR, type, arg));
       if (TREE_CODE (orig) == COMPLEX_TYPE)
        {
@@ -1942,9 +1965,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;
@@ -1953,7 +1976,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);
@@ -1961,7 +1984,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)
@@ -1985,19 +2008,49 @@ 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
-      || TREE_CODE (x) == REAL_CST
-      || TREE_CODE (x) == STRING_CST
-      || TREE_CODE (x) == ADDR_EXPR)
+  /* We only need to wrap lvalue tree codes.  */
+  switch (TREE_CODE (x))
+  {
+  case VAR_DECL:
+  case PARM_DECL:
+  case RESULT_DECL:
+  case LABEL_DECL:
+  case FUNCTION_DECL:
+  case SSA_NAME:
+
+  case COMPONENT_REF:
+  case INDIRECT_REF:
+  case ARRAY_REF:
+  case BIT_FIELD_REF:
+  case BUFFER_REF:
+  case ARRAY_RANGE_REF:
+  case VTABLE_REF:
+
+  case REALPART_EXPR:
+  case IMAGPART_EXPR:
+  case PREINCREMENT_EXPR:
+  case PREDECREMENT_EXPR:
+  case SAVE_EXPR:
+  case UNSAVE_EXPR:
+  case TRY_CATCH_EXPR:
+  case WITH_CLEANUP_EXPR:
+  case COMPOUND_EXPR:
+  case MODIFY_EXPR:
+  case TARGET_EXPR:
+  case COND_EXPR:
+  case BIND_EXPR:
+  case MIN_EXPR:
+  case MAX_EXPR:
+  case RTL_EXPR:
+    break;
+
+  default:
+    /* Assume the worst for front-end tree codes.  */
+    if ((int)TREE_CODE (x) >= NUM_TREE_CODES)
+      break;
     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.
@@ -2019,11 +2072,15 @@ pedantic_non_lvalue (tree x)
 \f
 /* Given a tree comparison code, return the code that is the logical inverse
    of the given code.  It is not safe to do this for floating-point
-   comparisons, except for NE_EXPR and EQ_EXPR.  */
+   comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode
+   as well: if reversing the comparison is unsafe, return ERROR_MARK.  */
 
 static enum tree_code
-invert_tree_comparison (enum tree_code code)
+invert_tree_comparison (enum tree_code code, bool honor_nans)
 {
+  if (honor_nans && flag_trapping_math)
+    return ERROR_MARK;
+
   switch (code)
     {
     case EQ_EXPR:
@@ -2031,13 +2088,29 @@ invert_tree_comparison (enum tree_code code)
     case NE_EXPR:
       return EQ_EXPR;
     case GT_EXPR:
-      return LE_EXPR;
+      return honor_nans ? UNLE_EXPR : LE_EXPR;
     case GE_EXPR:
-      return LT_EXPR;
+      return honor_nans ? UNLT_EXPR : LT_EXPR;
     case LT_EXPR:
-      return GE_EXPR;
+      return honor_nans ? UNGE_EXPR : GE_EXPR;
     case LE_EXPR:
+      return honor_nans ? UNGT_EXPR : GT_EXPR;
+    case LTGT_EXPR:
+      return UNEQ_EXPR;
+    case UNEQ_EXPR:
+      return LTGT_EXPR;
+    case UNGT_EXPR:
+      return LE_EXPR;
+    case UNGE_EXPR:
+      return LT_EXPR;
+    case UNLT_EXPR:
+      return GE_EXPR;
+    case UNLE_EXPR:
       return GT_EXPR;
+    case ORDERED_EXPR:
+      return UNORDERED_EXPR;
+    case UNORDERED_EXPR:
+      return ORDERED_EXPR;
     default:
       abort ();
     }
@@ -2072,7 +2145,7 @@ swap_tree_comparison (enum tree_code code)
    into a compcode bit-based encoding.  This function is the inverse of
    compcode_to_comparison.  */
 
-static int
+static enum comparison_code
 comparison_to_compcode (enum tree_code code)
 {
   switch (code)
@@ -2089,6 +2162,22 @@ comparison_to_compcode (enum tree_code code)
       return COMPCODE_NE;
     case GE_EXPR:
       return COMPCODE_GE;
+    case ORDERED_EXPR:
+      return COMPCODE_ORD;
+    case UNORDERED_EXPR:
+      return COMPCODE_UNORD;
+    case UNLT_EXPR:
+      return COMPCODE_UNLT;
+    case UNEQ_EXPR:
+      return COMPCODE_UNEQ;
+    case UNLE_EXPR:
+      return COMPCODE_UNLE;
+    case UNGT_EXPR:
+      return COMPCODE_UNGT;
+    case LTGT_EXPR:
+      return COMPCODE_LTGT;
+    case UNGE_EXPR:
+      return COMPCODE_UNGE;
     default:
       abort ();
     }
@@ -2099,7 +2188,7 @@ comparison_to_compcode (enum tree_code code)
    inverse of comparison_to_compcode.  */
 
 static enum tree_code
-compcode_to_comparison (int code)
+compcode_to_comparison (enum comparison_code code)
 {
   switch (code)
     {
@@ -2115,11 +2204,111 @@ compcode_to_comparison (int code)
       return NE_EXPR;
     case COMPCODE_GE:
       return GE_EXPR;
+    case COMPCODE_ORD:
+      return ORDERED_EXPR;
+    case COMPCODE_UNORD:
+      return UNORDERED_EXPR;
+    case COMPCODE_UNLT:
+      return UNLT_EXPR;
+    case COMPCODE_UNEQ:
+      return UNEQ_EXPR;
+    case COMPCODE_UNLE:
+      return UNLE_EXPR;
+    case COMPCODE_UNGT:
+      return UNGT_EXPR;
+    case COMPCODE_LTGT:
+      return LTGT_EXPR;
+    case COMPCODE_UNGE:
+      return UNGE_EXPR;
     default:
       abort ();
     }
 }
 
+/* Return a tree for the comparison which is the combination of
+   doing the AND or OR (depending on CODE) of the two operations LCODE
+   and RCODE on the identical operands LL_ARG and LR_ARG.  Take into account
+   the possibility of trapping if the mode has NaNs, and return NULL_TREE
+   if this makes the transformation invalid.  */
+
+tree
+combine_comparisons (enum tree_code code, enum tree_code lcode,
+                    enum tree_code rcode, tree truth_type,
+                    tree ll_arg, tree lr_arg)
+{
+  bool honor_nans = HONOR_NANS (TYPE_MODE (TREE_TYPE (ll_arg)));
+  enum comparison_code lcompcode = comparison_to_compcode (lcode);
+  enum comparison_code rcompcode = comparison_to_compcode (rcode);
+  enum comparison_code compcode;
+
+  switch (code)
+    {
+    case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR:
+      compcode = lcompcode & rcompcode;
+      break;
+
+    case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR:
+      compcode = lcompcode | rcompcode;
+      break;
+
+    default:
+      return NULL_TREE;
+    }
+
+  if (!honor_nans)
+    {
+      /* Eliminate unordered comparisons, as well as LTGT and ORD
+        which are not used unless the mode has NaNs.  */
+      compcode &= ~COMPCODE_UNORD;
+      if (compcode == COMPCODE_LTGT)
+       compcode = COMPCODE_NE;
+      else if (compcode == COMPCODE_ORD)
+       compcode = COMPCODE_TRUE;
+    }
+   else if (flag_trapping_math)
+     {
+       /* Check that the original operation and the optimized ones will trap 
+          under the same condition.  */
+       bool ltrap = (lcompcode & COMPCODE_UNORD) == 0
+                    && (lcompcode != COMPCODE_EQ)
+                    && (lcompcode != COMPCODE_ORD);
+       bool rtrap = (rcompcode & COMPCODE_UNORD) == 0
+                    && (rcompcode != COMPCODE_EQ)
+                    && (rcompcode != COMPCODE_ORD);
+       bool trap = (compcode & COMPCODE_UNORD) == 0
+                   && (compcode != COMPCODE_EQ)
+                   && (compcode != COMPCODE_ORD);
+
+        /* In a short-circuited boolean expression the LHS might be
+          such that the RHS, if evaluated, will never trap.  For
+          example, in ORD (x, y) && (x < y), we evaluate the RHS only
+          if neither x nor y is NaN.  (This is a mixed blessing: for
+          example, the expression above will never trap, hence
+          optimizing it to x < y would be invalid).  */
+        if ((code == TRUTH_ORIF_EXPR && (lcompcode & COMPCODE_UNORD))
+            || (code == TRUTH_ANDIF_EXPR && !(lcompcode & COMPCODE_UNORD)))
+          rtrap = false;
+
+        /* If the comparison was short-circuited, and only the RHS
+          trapped, we may now generate a spurious trap.  */
+       if (rtrap && !ltrap
+           && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR))
+         return NULL_TREE;
+
+       /* If we changed the conditions that cause a trap, we lose.  */
+       if ((ltrap || rtrap) != trap)
+         return NULL_TREE;
+      }
+
+  if (compcode == COMPCODE_TRUE)
+    return constant_boolean_node (true, truth_type);
+  else if (compcode == COMPCODE_FALSE)
+    return constant_boolean_node (false, truth_type);
+  else
+    return fold (build2 (compcode_to_comparison (compcode),
+                        truth_type, ll_arg, lr_arg));
+}
+
 /* Return nonzero if CODE is a tree code that represents a truth value.  */
 
 static int
@@ -2133,16 +2322,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 behavior 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
@@ -2151,13 +2340,15 @@ 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;
@@ -2186,7 +2377,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;
@@ -2220,7 +2411,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
          while (v1 && v2)
            {
              if (!operand_equal_p (TREE_VALUE (v1), TREE_VALUE (v2),
-                                   only_const))
+                                   flags))
                return 0;
              v1 = TREE_CHAIN (v1);
              v2 = TREE_CHAIN (v2);
@@ -2231,9 +2422,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)
@@ -2248,7 +2439,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)))
@@ -2261,7 +2452,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const)
        return 0;
 
       return operand_equal_p (TREE_OPERAND (arg0, 0),
-                             TREE_OPERAND (arg1, 0), 0);
+                             TREE_OPERAND (arg1, 0), flags);
 
     case '<':
     case '2':
@@ -2273,9 +2464,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
@@ -2288,23 +2479,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;
        }
@@ -2315,7 +2506,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));
@@ -2324,14 +2515,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
@@ -2340,7 +2535,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);
@@ -2356,11 +2552,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;
@@ -2547,11 +2743,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)
@@ -2563,13 +2759,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;
        }
@@ -2594,7 +2790,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:
@@ -2615,7 +2811,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);
 }
@@ -2628,15 +2824,40 @@ 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);
 }
+
+/* Return a tree for the case when the result of an expression is RESULT
+   converted to TYPE and OMITTED1 and OMITTED2 were previously operands
+   of the expression but are now not needed.
+
+   If OMITTED1 or OMITTED2 has side effects, they must be evaluated.
+   If both OMITTED1 and OMITTED2 have side effects, OMITTED1 is
+   evaluated before OMITTED2.  Otherwise, if neither has side effects,
+   just do the conversion of RESULT to TYPE.  */
+
+tree
+omit_two_operands (tree type, tree result, tree omitted1, tree omitted2)
+{
+  tree t = fold_convert (type, result);
+
+  if (TREE_SIDE_EFFECTS (omitted2))
+    t = build2 (COMPOUND_EXPR, type, omitted2, t);
+  if (TREE_SIDE_EFFECTS (omitted1))
+    t = build2 (COMPOUND_EXPR, type, omitted1, t);
+
+  return TREE_CODE (t) != COMPOUND_EXPR ? non_lvalue (t) : t;
+}
+
 \f
 /* Return a simplified tree node for the truth-negation of ARG.  This
    never alters ARG itself.  We assume that ARG is an operation that
-   returns a truth value (0 or 1).  */
+   returns a truth value (0 or 1).
 
+   FIXME: one would think we would fold the result, but it causes
+   problems with the dominator optimizer.  */
 tree
 invert_truthvalue (tree arg)
 {
@@ -2652,22 +2873,22 @@ invert_truthvalue (tree arg)
 
   if (TREE_CODE_CLASS (code) == '<')
     {
-      if (FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
-         && !flag_unsafe_math_optimizations
-         && 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)
+      tree op_type = TREE_TYPE (TREE_OPERAND (arg, 0));
+      if (FLOAT_TYPE_P (op_type)
+         && flag_trapping_math
+         && code != ORDERED_EXPR && code != UNORDERED_EXPR
+         && code != NE_EXPR && code != EQ_EXPR)
        return build1 (TRUTH_NOT_EXPR, type, arg);
       else
-       return build (invert_tree_comparison (code), type,
-                     TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1));
+       {
+         code = invert_tree_comparison (code,
+                                        HONOR_NANS (TYPE_MODE (op_type)));
+         if (code == ERROR_MARK)
+           return build1 (TRUTH_NOT_EXPR, type, arg);
+         else
+           return build2 (code, type,
+                          TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1));
+       }
     }
 
   switch (code)
@@ -2676,14 +2897,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
@@ -2692,39 +2913,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)));
+      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,
@@ -2733,8 +2957,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);
@@ -2799,8 +3023,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
@@ -2810,8 +3034,8 @@ 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));
 
   BIT_FIELD_REF_UNSIGNED (result) = unsignedp;
 
@@ -2916,15 +3140,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
@@ -2943,9 +3167,7 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
        {
          warning ("comparison is always %d due to width of bit-field",
                   code == NE_EXPR);
-         return fold_convert (compare_type,
-                              (code == NE_EXPR
-                               ? integer_one_node : integer_zero_node));
+         return constant_boolean_node (code == NE_EXPR, compare_type);
        }
     }
   else
@@ -2956,9 +3178,7 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
        {
          warning ("comparison is always %d due to width of bit-field",
                   code == NE_EXPR);
-         return fold_convert (compare_type,
-                              (code == NE_EXPR
-                               ? integer_one_node : integer_zero_node));
+         return constant_boolean_node (code == NE_EXPR, compare_type);
        }
     }
 
@@ -2985,9 +3205,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.
@@ -3074,8 +3294,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;
@@ -3240,8 +3460,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;
     }
@@ -3281,7 +3501,7 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
       abort ();
     }
 
-  return fold_convert (type, result ? integer_one_node : integer_zero_node);
+  return constant_boolean_node (result, type);
 }
 \f
 /* Given EXP, a logical expression, set the range it is testing into
@@ -3416,8 +3636,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:
@@ -3498,11 +3718,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
@@ -3575,13 +3795,13 @@ 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))
     {
@@ -3620,15 +3840,15 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
              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);
 
@@ -3817,10 +4037,10 @@ 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
               && ! CONTAINS_PLACEHOLDER_P (lhs))
@@ -3833,9 +4053,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);
        }
     }
 
@@ -3949,17 +4169,20 @@ 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;
 
-  code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR)
-         ? TRUTH_AND_EXPR : TRUTH_OR_EXPR);
-
   ll_arg = TREE_OPERAND (lhs, 0);
   lr_arg = TREE_OPERAND (lhs, 1);
   rl_arg = TREE_OPERAND (rhs, 0);
@@ -3967,46 +4190,31 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
 
   /* Simplify (x<y) && (x==y) into (x<=y) and related optimizations.  */
   if (simple_operand_p (ll_arg)
-      && simple_operand_p (lr_arg)
-      && !FLOAT_TYPE_P (TREE_TYPE (ll_arg)))
+      && simple_operand_p (lr_arg))
     {
-      int compcode;
-
+      tree result;
       if (operand_equal_p (ll_arg, rl_arg, 0)
           && operand_equal_p (lr_arg, rr_arg, 0))
-        {
-          int lcompcode, rcompcode;
-
-          lcompcode = comparison_to_compcode (lcode);
-          rcompcode = comparison_to_compcode (rcode);
-          compcode = (code == TRUTH_AND_EXPR)
-                     ? lcompcode & rcompcode
-                     : lcompcode | rcompcode;
-        }
+       {
+          result = combine_comparisons (code, lcode, rcode,
+                                       truth_type, ll_arg, lr_arg);
+         if (result)
+           return result;
+       }
       else if (operand_equal_p (ll_arg, rr_arg, 0)
                && operand_equal_p (lr_arg, rl_arg, 0))
-        {
-          int lcompcode, rcompcode;
-
-          rcode = swap_tree_comparison (rcode);
-          lcompcode = comparison_to_compcode (lcode);
-          rcompcode = comparison_to_compcode (rcode);
-          compcode = (code == TRUTH_AND_EXPR)
-                     ? lcompcode & rcompcode
-                     : lcompcode | rcompcode;
-        }
-      else
-       compcode = -1;
-
-      if (compcode == COMPCODE_TRUE)
-       return fold_convert (truth_type, integer_one_node);
-      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);
+       {
+          result = combine_comparisons (code, lcode,
+                                       swap_tree_comparison (rcode),
+                                       truth_type, ll_arg, lr_arg);
+         if (result)
+           return result;
+       }
     }
 
+  code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR)
+         ? TRUTH_AND_EXPR : TRUTH_OR_EXPR);
+
   /* If the RHS can be evaluated unconditionally and its operands are
      simple, it wins to evaluate the RHS unconditionally on machines
      with expensive branches.  In this case, this isn't a comparison
@@ -4023,22 +4231,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),
+                      fold_convert (TREE_TYPE (ll_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),
+                      fold_convert (TREE_TYPE (ll_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
@@ -4158,9 +4366,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
        {
          warning ("comparison is always %d", wanted_code == NE_EXPR);
 
-         return fold_convert (truth_type,
-                              wanted_code == NE_EXPR
-                              ? integer_one_node : integer_zero_node);
+         return constant_boolean_node (wanted_code == NE_EXPR, truth_type);
        }
     }
   if (r_const)
@@ -4175,9 +4381,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
        {
          warning ("comparison is always %d", wanted_code == NE_EXPR);
 
-         return fold_convert (truth_type,
-                              wanted_code == NE_EXPR
-                              ? integer_one_node : integer_zero_node);
+         return constant_boolean_node (wanted_code == NE_EXPR, truth_type);
        }
     }
 
@@ -4229,14 +4433,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
@@ -4282,12 +4486,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;
@@ -4305,12 +4509,12 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
       if (wanted_code == NE_EXPR)
        {
          warning ("`or' of unmatched not-equal tests is always 1");
-         return fold_convert (truth_type, integer_one_node);
+         return constant_boolean_node (true, truth_type);
        }
       else
        {
          warning ("`and' of mutually exclusive equal-tests is always 0");
-         return fold_convert (truth_type, integer_zero_node);
+         return constant_boolean_node (false, truth_type);
        }
     }
 
@@ -4323,10 +4527,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
@@ -4370,20 +4574,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  */
@@ -4391,7 +4595,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  */
@@ -4399,13 +4603,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  */
@@ -4418,7 +4622,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;
@@ -4553,8 +4757,8 @@ 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;
 
@@ -4572,9 +4776,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;
 
@@ -4591,8 +4795,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.  */
@@ -4642,17 +4846,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;
 
@@ -4674,12 +4878,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;
 
@@ -4689,7 +4893,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
@@ -4708,15 +4912,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;
 
@@ -4727,40 +4931,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.  */
 
@@ -4781,25 +4951,6 @@ 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)'
@@ -4816,53 +4967,13 @@ 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 (TREE_CODE (cond) != COND_EXPR
-      && TREE_CODE_CLASS (code) == '<')
-    return NULL_TREE;
-
-  if (TREE_CODE (arg) == COND_EXPR
-      && count_cond (cond, 25) + count_cond (arg, 25) > 25)
-    return NULL_TREE;
 
-  if (TREE_SIDE_EFFECTS (arg)
-      && (lang_hooks.decls.global_bindings_p () != 0
-         || CONTAINS_PLACEHOLDER_P (arg)))
+  /* 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 (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;
-    }
-
   if (TREE_CODE (cond) == COND_EXPR)
     {
       test = TREE_OPERAND (cond, 0);
@@ -4870,91 +4981,29 @@ 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
     {
       tree testtype = TREE_TYPE (cond);
       test = cond;
-      true_value = fold_convert (testtype, integer_one_node);
-      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);
-       }
+      true_value = constant_boolean_node (true, testtype);
+      false_value = constant_boolean_node (false, testtype);
     }
 
   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
@@ -5023,20 +5072,16 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
        {
          /* sqrt(x) < y is always false, if y is negative.  */
          if (code == EQ_EXPR || code == LT_EXPR || code == LE_EXPR)
-           return omit_one_operand (type,
-                                    fold_convert (type, integer_zero_node),
-                                    arg);
+           return omit_one_operand (type, integer_zero_node, arg);
 
          /* sqrt(x) > y is always true, if y is negative and we
             don't care about NaNs, i.e. negative values of x.  */
          if (code == NE_EXPR || !HONOR_NANS (mode))
-           return omit_one_operand (type,
-                                    fold_convert (type, integer_one_node),
-                                    arg);
+           return omit_one_operand (type, integer_one_node, 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)
        {
@@ -5049,19 +5094,17 @@ 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.  */
-             return omit_one_operand (type,
-                                      fold_convert (type, integer_zero_node),
-                                      arg);
+             return omit_one_operand (type, integer_zero_node, arg);
            }
 
          /* 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)
        {
@@ -5075,21 +5118,19 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
              /* sqrt(x) < y is always true, when y is a very large
                 value and we don't care about NaNs or Infinities.  */
              if (! HONOR_NANS (mode) && ! HONOR_INFINITIES (mode))
-               return omit_one_operand (type,
-                                        fold_convert (type, integer_one_node),
-                                        arg);
+               return omit_one_operand (type, integer_one_node, arg);
 
              /* 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
@@ -5097,32 +5138,32 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
                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
              && ! 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)))));
            }
        }
     }
@@ -5161,23 +5202,19 @@ fold_inf_compare (enum tree_code code, tree type, tree arg0, tree arg1)
       /* x > +Inf is always false, if with ignore sNANs.  */
       if (HONOR_SNANS (mode))
         return NULL_TREE;
-      return omit_one_operand (type,
-                              fold_convert (type, integer_zero_node),
-                              arg0);
+      return omit_one_operand (type, integer_zero_node, arg0);
 
     case LE_EXPR:
       /* x <= +Inf is always true, if we don't case about NaNs.  */
       if (! HONOR_NANS (mode))
-       return omit_one_operand (type,
-                                fold_convert (type, integer_one_node),
-                                arg0);
+       return omit_one_operand (type, integer_one_node, arg0);
 
       /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
       if (lang_hooks.decls.global_bindings_p () == 0
          && ! CONTAINS_PLACEHOLDER_P (arg0))
        {
          arg0 = save_expr (arg0);
-         return fold (build (EQ_EXPR, type, arg0, arg0));
+         return fold (build2 (EQ_EXPR, type, arg0, arg0));
        }
       break;
 
@@ -5185,23 +5222,29 @@ 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)));
+
+      /* The transformation below creates non-gimple code and thus is
+        not appropriate if we are in gimple form.  */
+      if (in_gimple_form)
+       return NULL_TREE;
+       
+      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:
@@ -5211,6 +5254,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 nonzero 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
@@ -5252,18 +5445,18 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
       /* If we have (A & C) != 0 where C is the sign bit of A, convert
         this into A < 0.  Similarly for (A & C) == 0 into A >= 0.  */
       arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
-      if (arg00 != NULL_TREE)
+      if (arg00 != NULL_TREE
+         /* This is only a win if casting to a signed type is cheap,
+            i.e. when arg00's type is not a partial mode.  */
+         && TYPE_PRECISION (TREE_TYPE (arg00))
+            == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg00))))
        {
          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)));
+         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.  */
-      if (TYPE_PRECISION (type) - 1 == bitnum)
-       abort ();
-      
       /* Otherwise we have (A & C) != 0 where C is a single bit, 
         convert that into ((A >> C2) & 1).  Where C2 = log2(C).
         Similarly for (A & C) == 0.  */
@@ -5296,16 +5489,16 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
       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);
@@ -5372,6 +5565,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;
 }
 
@@ -5398,6 +5600,7 @@ fold (tree expr)
   tree arg0 = NULL_TREE, arg1 = NULL_TREE;
   enum tree_code code = TREE_CODE (t);
   int kind = TREE_CODE_CLASS (code);
+
   /* WINS will be nonzero when the switch is done
      if all operands are constant.  */
   int wins = 1;
@@ -5485,8 +5688,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, TREE_OPERAND (t, 1),
-                       TREE_OPERAND (t, 0)));
+    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,
@@ -5517,10 +5720,11 @@ fold (tree expr)
                  || (TREE_CODE (arg0) == BIT_AND_EXPR
                      && integer_onep (TREE_OPERAND (arg0, 1)))))))
     {
-      tem = 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)
        tem = invert_truthvalue (tem);
@@ -5531,8 +5735,8 @@ fold (tree expr)
   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);
@@ -5541,8 +5745,8 @@ fold (tree expr)
            arg01 = fold (build1 (code, type, arg01));
          if (! VOID_TYPE_P (TREE_TYPE (arg02)))
            arg02 = fold (build1 (code, type, arg02));
-         tem = 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
@@ -5567,38 +5771,50 @@ fold (tree expr)
                        (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))))
                    && TYPE_PRECISION (TREE_TYPE (tem)) <= BITS_PER_WORD))
            tem = build1 (code, type,
-                         build (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)));
+                         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 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)));
       if (TREE_CODE (arg1) == COMPOUND_EXPR
          && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
-       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))));
 
       if (TREE_CODE (arg0) == COND_EXPR
          || TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
@@ -5630,6 +5846,7 @@ fold (tree expr)
     case FIX_TRUNC_EXPR:
     case FIX_CEIL_EXPR:
     case FIX_FLOOR_EXPR:
+    case FIX_ROUND_EXPR:
       if (TREE_TYPE (TREE_OPERAND (t, 0)) == type)
        return TREE_OPERAND (t, 0);
 
@@ -5727,8 +5944,8 @@ fold (tree expr)
          tem = copy_node (t);
          TREE_OPERAND (tem, 0) = TREE_OPERAND (prev, 1);
          /* First do the assignment, then return converted constant.  */
-         tem = build (COMPOUND_EXPR, TREE_TYPE (tem), prev, fold (tem));
-         TREE_NO_UNUSED_WARNING (tem) = 1;
+         tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), prev, fold (tem));
+         TREE_NO_WARNING (tem) = 1;
          TREE_USED (tem) = 1;
          return tem;
        }
@@ -5771,9 +5988,29 @@ fold (tree expr)
 #endif
            }
          if (change)
-           return fold (build (BIT_AND_EXPR, type,
-                               fold_convert (type, and0),
-                               fold_convert (type, 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, type, arg0);
@@ -5800,6 +6037,7 @@ fold (tree expr)
        {
          tem = copy_node (t);
          TREE_CONSTANT (tem) = wins;
+         TREE_INVARIANT (tem) = wins;
          return tem;
        }
       return t;
@@ -5810,8 +6048,7 @@ fold (tree expr)
       return t;
 
     case ABS_EXPR:
-      if (wins
-         && (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST))
+      if (TREE_CODE (arg0) == INTEGER_CST || TREE_CODE (arg0) == REAL_CST)
        return fold_abs_const (arg0, type);
       else if (TREE_CODE (arg0) == NEGATE_EXPR)
        return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0)));
@@ -5833,33 +6070,25 @@ 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;
 
     case BIT_NOT_EXPR:
-      if (wins)
-       {
-         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;
-       }
+      if (TREE_CODE (arg0) == INTEGER_CST)
+        return fold_not_const (arg0, type);
       else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
        return TREE_OPERAND (arg0, 0);
       return t;
@@ -5867,11 +6096,11 @@ 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
          && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
-       return fold (build (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
+       return fold (build2 (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
       if (! FLOAT_TYPE_P (type))
        {
          if (integer_zerop (arg1))
@@ -5914,18 +6143,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)
@@ -5976,17 +6205,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
@@ -6002,8 +6232,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
@@ -6016,8 +6246,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).  */
@@ -6031,8 +6261,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).  */
@@ -6051,9 +6281,9 @@ 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
@@ -6066,8 +6296,8 @@ fold (tree expr)
                  && TREE_CODE (tree10) == MULT_EXPR)
                 {
                   tree tree0;
-                  tree0 = fold (build (PLUS_EXPR, type, arg0, tree10));
-                  return fold (build (PLUS_EXPR, type, tree0, tree11));
+                  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) */
@@ -6081,8 +6311,8 @@ fold (tree expr)
                  && TREE_CODE (tree00) == MULT_EXPR)
                 {
                   tree tree0;
-                  tree0 = fold (build (PLUS_EXPR, type, tree01, arg1));
-                  return fold (build (PLUS_EXPR, type, tree00, tree0));
+                  tree0 = fold (build2 (PLUS_EXPR, type, tree01, arg1));
+                  return fold (build2 (PLUS_EXPR, type, tree00, tree0));
                 }
             }
        }
@@ -6117,8 +6347,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;
@@ -6132,10 +6362,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)
              {
@@ -6150,10 +6380,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);
              }
          }
       }
@@ -6256,15 +6486,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))
        {
@@ -6278,15 +6508,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
@@ -6302,9 +6532,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));
                }
            }
        }
@@ -6333,7 +6563,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
@@ -6342,19 +6572,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;
@@ -6362,13 +6592,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))
        {
@@ -6380,12 +6610,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),
@@ -6423,8 +6653,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)
@@ -6447,7 +6677,7 @@ fold (tree expr)
 
                  /* Optimize root(x)*root(y) as root(x*y).  */
                  rootfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                 arg = fold (build (MULT_EXPR, type, arg00, arg10));
+                 arg = fold (build2 (MULT_EXPR, type, arg00, arg10));
                  arglist = build_tree_list (NULL_TREE, arg);
                  return build_function_call_expr (rootfn, arglist);
                }
@@ -6456,9 +6686,9 @@ fold (tree expr)
              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);
                }
@@ -6479,7 +6709,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));
@@ -6490,7 +6720,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));
@@ -6605,9 +6835,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
@@ -6675,9 +6905,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;
@@ -6692,13 +6922,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)))
@@ -6720,7 +6950,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)
            {
@@ -6729,24 +6959,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
@@ -6757,8 +6987,8 @@ 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)
@@ -6772,7 +7002,7 @@ fold (tree expr)
              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).  */
@@ -6787,7 +7017,7 @@ fold (tree expr)
              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));
            }
        }
 
@@ -6823,9 +7053,8 @@ fold (tree expr)
                {
                  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));
                }
            }
 
@@ -6879,7 +7108,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,
@@ -6940,7 +7169,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
@@ -6951,11 +7180,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.  */
@@ -6975,7 +7204,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;
 
@@ -6984,11 +7213,15 @@ 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;
 
     case TRUTH_NOT_EXPR:
+      /* The argument to invert_truthvalue must have Boolean type.  */
+      if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
+          arg0 = fold_convert (boolean_type_node, arg0);
+      
       /* Note that the operand of this must be an int
         and its values must be 0 or 1.
         ("true" is a fixed value perhaps depending on the language,
@@ -7056,23 +7289,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.  */
@@ -7085,7 +7318,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;
@@ -7128,6 +7361,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:
@@ -7138,7 +7374,7 @@ 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 this is an equality comparison of the address of a non-weak
         object against zero, then we know the result.  */
@@ -7147,12 +7383,7 @@ fold (tree expr)
          && DECL_P (TREE_OPERAND (arg0, 0))
          && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
          && integer_zerop (arg1))
-       {
-         if (code == EQ_EXPR)
-           return fold_convert (type, integer_zero_node);
-         else
-           return fold_convert (type, integer_one_node);
-       }
+       return constant_boolean_node (code != EQ_EXPR, type);
 
       /* If this is an equality comparison of the address of two non-weak,
         unaliased symbols neither of which are extern (since we do not
@@ -7170,14 +7401,9 @@ fold (tree expr)
          && ! 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));
-       }
+       return constant_boolean_node (operand_equal_p (arg0, arg1, 0)
+                                     ? code == EQ_EXPR : code != EQ_EXPR,
+                                     type);
 
       if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
        {
@@ -7190,14 +7416,14 @@ fold (tree expr)
 
          /* 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)
          {
@@ -7207,23 +7433,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))))
              {
                tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
-               return omit_one_operand (type, fold_convert (type, tem), arg0);
+               return omit_one_operand (type, tem, arg0);
              }
 
            /* Fold comparisons against infinity.  */
@@ -7248,7 +7474,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.
@@ -7260,8 +7486,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
@@ -7352,11 +7578,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;
@@ -7364,7 +7590,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)));
 
@@ -7395,20 +7625,16 @@ fold (tree expr)
              switch (code)
                {
                case GT_EXPR:
-                 return omit_one_operand (type,
-                                          fold_convert (type,
-                                                        integer_zero_node),
-                                          arg0);
+                 return omit_one_operand (type, 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,
-                                          fold_convert (type,
-                                                        integer_one_node),
-                                          arg0);
+                 return omit_one_operand (type, 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.  */
@@ -7422,10 +7648,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;
                }
@@ -7434,20 +7660,16 @@ fold (tree expr)
              switch (code)
                {
                case LT_EXPR:
-                 return omit_one_operand (type,
-                                          fold_convert (type,
-                                                        integer_zero_node),
-                                          arg0);
+                 return omit_one_operand (type, 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,
-                                          fold_convert (type,
-                                                        integer_one_node),
-                                          arg0);
+                 return omit_one_operand (type, 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;
@@ -7458,15 +7680,16 @@ 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
                     && TYPE_UNSIGNED (TREE_TYPE (arg1))
                     /* signed_type does not work on pointer types.  */
@@ -7480,9 +7703,9 @@ fold (tree expr)
                    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)));
                  }
              }
          }
@@ -7500,7 +7723,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)
@@ -7509,14 +7732,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
@@ -7531,8 +7754,8 @@ fold (tree expr)
               && (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.  */
@@ -7553,10 +7776,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
@@ -7566,30 +7790,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
@@ -7605,13 +7827,13 @@ fold (tree 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)));
+         tree newmod = build2 (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));
+         return build2 (code, type, newmod, fold_convert (newtype, arg1));
        }
 
       /* If this is an NE comparison of zero with an AND of one, remove the
@@ -7627,8 +7849,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.  */
@@ -7644,10 +7866,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);
@@ -7661,9 +7883,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);
@@ -7675,10 +7897,10 @@ fold (tree expr)
          && 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)
               && TYPE_UNSIGNED (TREE_TYPE (arg0))
@@ -7687,12 +7909,12 @@ fold (tree 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.)  */
@@ -7711,7 +7933,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
@@ -7765,17 +7987,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
@@ -7820,7 +8045,7 @@ fold (tree expr)
                      return omit_one_operand (type, integer_one_node, arg0);
                    }
 
-                 tem = build (code, type, cval1, cval2);
+                 tem = build2 (code, type, cval1, cval2);
                  if (save_p)
                    return save_expr (tem);
                  else
@@ -7864,11 +8089,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
@@ -7891,10 +8116,24 @@ 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));
+       }
+
+      /* 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))
+       {
+         t1 = fold_div_compare (code, type, arg0, arg1);
+         if (t1 != NULL_TREE)
+           return t1;
        }
 
       /* Both ARG0 and ARG1 are known to be constants at this point.  */
@@ -8052,21 +8291,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 ();
@@ -8087,47 +8326,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;
@@ -8147,8 +8394,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.  */
@@ -8178,7 +8425,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)));
 
@@ -8186,8 +8433,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))
@@ -8197,8 +8444,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;
@@ -8227,11 +8474,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:
@@ -8243,11 +8490,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
@@ -8277,15 +8524,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;
@@ -8484,13 +8731,18 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
       fold_checksum_tree (DECL_VINDEX (expr), ctx, ht);
       break;
     case 't':
-      fold_checksum_tree (TYPE_VALUES (expr), ctx, ht);
+      if (TREE_CODE (expr) == ENUMERAL_TYPE)
+        fold_checksum_tree (TYPE_VALUES (expr), ctx, ht);
       fold_checksum_tree (TYPE_SIZE (expr), ctx, ht);
       fold_checksum_tree (TYPE_SIZE_UNIT (expr), ctx, ht);
       fold_checksum_tree (TYPE_ATTRIBUTES (expr), ctx, ht);
       fold_checksum_tree (TYPE_NAME (expr), ctx, ht);
-      fold_checksum_tree (TYPE_MIN_VALUE (expr), ctx, ht);
-      fold_checksum_tree (TYPE_MAX_VALUE (expr), ctx, ht);
+      if (INTEGRAL_TYPE_P (expr)
+          || SCALAR_FLOAT_TYPE_P (expr))
+       {
+         fold_checksum_tree (TYPE_MIN_VALUE (expr), ctx, ht);
+         fold_checksum_tree (TYPE_MAX_VALUE (expr), ctx, ht);
+       }
       fold_checksum_tree (TYPE_MAIN_VARIANT (expr), ctx, ht);
       fold_checksum_tree (TYPE_BINFO (expr), ctx, ht);
       fold_checksum_tree (TYPE_CONTEXT (expr), ctx, ht);
@@ -8800,13 +9052,18 @@ tree_expr_nonnegative_p (tree t)
            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_BUILTIN_F (BUILT_IN_SQRT)
+             /* sqrt(-0.0) is -0.0.  */
+             if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
+               return 1;
+             return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
            CASE_BUILTIN_F (BUILT_IN_ASINH)
            CASE_BUILTIN_F (BUILT_IN_ATAN)
            CASE_BUILTIN_F (BUILT_IN_ATANH)
@@ -8833,17 +9090,17 @@ tree_expr_nonnegative_p (tree t)
              /* True if the 1st argument is nonnegative.  */
              return tree_expr_nonnegative_p (TREE_VALUE (arglist));
 
-           CASE_BUILTIN_F(BUILT_IN_FMAX)
+           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)
+           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)
+           CASE_BUILTIN_F (BUILT_IN_COPYSIGN)
              /* True if the 2nd argument is nonnegative.  */
              return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
 
@@ -8875,7 +9132,7 @@ tree_expr_nonzero_p (tree t)
 {
   tree type = TREE_TYPE (t);
 
-  /* Doing something usefull for floating point would need more work.  */
+  /* Doing something useful for floating point would need more work.  */
   if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
     return false;
 
@@ -9013,6 +9270,575 @@ 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, integer_zero_node, op0);
+
+         case GE_EXPR:
+           *code_p = EQ_EXPR;
+           break;
+         case LE_EXPR:
+           return omit_one_operand (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, integer_zero_node, op0);
+
+         case LE_EXPR:
+           *code_p = EQ_EXPR;
+           break;
+
+         case GE_EXPR:
+           return omit_one_operand (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)
+       return constant_boolean_node (true, type);
+      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)
+       return constant_boolean_node (false, type);
+      return NULL_TREE;
+
+    case TRUTH_XOR_EXPR:
+      if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST)
+       {
+         int x = ! integer_zerop (op0) ^ ! integer_zerop (op1);
+         return constant_boolean_node (x, type);
+       }
+      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)
+{
+  /* 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)
+       return fold_not_const (op0, type);
+      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 fold_convert (TREE_TYPE (exp),
+                            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.
 
@@ -9053,7 +9879,7 @@ fold_negate_const (tree arg0, tree type)
 
    TYPE is the type of the result.  */
 
-static tree
+tree
 fold_abs_const (tree arg0, tree type)
 {
   tree t = NULL_TREE;
@@ -9101,6 +9927,31 @@ fold_abs_const (tree arg0, tree type)
   return t;
 }
 
+/* Return the tree for not (ARG0) when ARG0 is known to be an integer
+   constant.  TYPE is the type of the result.  */
+
+static tree
+fold_not_const (tree arg0, tree type)
+{
+  tree t = NULL_TREE;
+
+  if (TREE_CODE (arg0) == INTEGER_CST)
+    {
+      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);
+    }
+#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
@@ -9136,7 +9987,7 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
   if (code == NE_EXPR || code == GE_EXPR)
     {
       invert = 1;
-      code = invert_tree_comparison (code);
+      code = invert_tree_comparison (code, false);
     }
 
   /* Compute a result for LT or EQ if args permit;
@@ -9188,8 +10039,77 @@ fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
 
   TREE_TYPE (tem) = type;
   if (TREE_CODE (type) == BOOLEAN_TYPE)
-    return (*lang_hooks.truthvalue_conversion) (tem);
+    return lang_hooks.truthvalue_conversion (tem);
   return tem;
 }
 
+/* Build an expression for the address of T.  Folds away INDIRECT_REF to
+   avoid confusing the gimplify process.  */
+
+tree
+build_fold_addr_expr_with_type (tree t, tree ptrtype)
+{
+  if (TREE_CODE (t) == INDIRECT_REF)
+    {
+      t = TREE_OPERAND (t, 0);
+      if (TREE_TYPE (t) != ptrtype)
+       t = build1 (NOP_EXPR, ptrtype, t);
+    }
+  else
+    {
+      tree base = t;
+      while (TREE_CODE (base) == COMPONENT_REF
+            || TREE_CODE (base) == ARRAY_REF)
+       base = TREE_OPERAND (base, 0);
+      if (DECL_P (base))
+       TREE_ADDRESSABLE (base) = 1;
+
+      t = build1 (ADDR_EXPR, ptrtype, t);
+    }
+
+  return t;
+}
+
+tree
+build_fold_addr_expr (tree t)
+{
+  return build_fold_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
+}
+
+/* Builds an expression for an indirection through T, simplifying some
+   cases.  */
+
+tree
+build_fold_indirect_ref (tree t)
+{
+  tree type = TREE_TYPE (TREE_TYPE (t));
+  tree sub = t;
+  tree subtype;
+
+  STRIP_NOPS (sub);
+  if (TREE_CODE (sub) == ADDR_EXPR)
+    {
+      tree op = TREE_OPERAND (sub, 0);
+      tree optype = TREE_TYPE (op);
+      /* *&p => p */
+      if (lang_hooks.types_compatible_p (type, optype))
+       return op;
+      /* *(foo *)&fooarray => fooarray[0] */
+      else if (TREE_CODE (optype) == ARRAY_TYPE
+              && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+       return build2 (ARRAY_REF, type, op, size_zero_node);
+    }
+
+  /* *(foo *)fooarrptr => (*fooarrptr)[0] */
+  subtype = TREE_TYPE (sub);
+  if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
+      && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+    {
+      sub = build_fold_indirect_ref (sub);
+      return build2 (ARRAY_REF, type, sub, size_zero_node);
+    }
+
+  return build1 (INDIRECT_REF, type, t);
+}
+
 #include "gt-fold-const.h"