OSDN Git Service

2005-04-02 Daniel Berlin <dberlin@dberlin.org>
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 517c45d..efbf8ed 100644 (file)
@@ -113,15 +113,16 @@ static tree make_range (tree, int *, tree *, tree *);
 static tree build_range_check (tree, tree, int, tree, tree);
 static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree,
                         tree);
-static tree fold_range_test (tree);
+static tree fold_range_test (enum tree_code, tree, tree, tree);
 static tree fold_cond_expr_with_comparison (tree, tree, tree, tree);
 static tree unextend (tree, int, int, tree);
 static tree fold_truthop (enum tree_code, tree, tree, tree);
-static tree optimize_minmax_comparison (tree);
+static tree optimize_minmax_comparison (enum tree_code, tree, tree, tree);
 static tree extract_muldiv (tree, tree, enum tree_code, tree);
 static tree extract_muldiv_1 (tree, tree, enum tree_code, tree);
 static int multiple_of_p (tree, tree, tree);
-static tree fold_binary_op_with_conditional_arg (tree, enum tree_code, 
+static tree fold_binary_op_with_conditional_arg (enum tree_code, tree,
+                                                tree, 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,
@@ -1043,8 +1044,8 @@ negate_expr (tree t)
                                     TREE_OPERAND (t, 1)))
            {
              tem = negate_expr (TREE_OPERAND (t, 1));
-             tem = fold (build2 (MINUS_EXPR, TREE_TYPE (t),
-                                 tem, TREE_OPERAND (t, 0)));
+             tem = fold_build2 (MINUS_EXPR, TREE_TYPE (t),
+                                tem, TREE_OPERAND (t, 0));
              return fold_convert (type, tem);
            }
 
@@ -1052,8 +1053,8 @@ negate_expr (tree t)
          if (negate_expr_p (TREE_OPERAND (t, 0)))
            {
              tem = negate_expr (TREE_OPERAND (t, 0));
-             tem = fold (build2 (MINUS_EXPR, TREE_TYPE (t),
-                                 tem, TREE_OPERAND (t, 1)));
+             tem = fold_build2 (MINUS_EXPR, TREE_TYPE (t),
+                                tem, TREE_OPERAND (t, 1));
              return fold_convert (type, tem);
            }
        }
@@ -1064,9 +1065,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 (build2 (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:
@@ -1081,15 +1082,15 @@ negate_expr (tree t)
          tem = TREE_OPERAND (t, 1);
          if (negate_expr_p (tem))
            return fold_convert (type,
-                                fold (build2 (TREE_CODE (t), TREE_TYPE (t),
-                                              TREE_OPERAND (t, 0),
-                                              negate_expr (tem))));
+                                fold_build2 (TREE_CODE (t), TREE_TYPE (t),
+                                             TREE_OPERAND (t, 0),
+                                             negate_expr (tem)));
          tem = TREE_OPERAND (t, 0);
          if (negate_expr_p (tem))
            return fold_convert (type,
-                                fold (build2 (TREE_CODE (t), TREE_TYPE (t),
-                                              negate_expr (tem),
-                                              TREE_OPERAND (t, 1))));
+                                fold_build2 (TREE_CODE (t), TREE_TYPE (t),
+                                             negate_expr (tem),
+                                             TREE_OPERAND (t, 1)));
        }
       break;
 
@@ -1130,7 +1131,7 @@ negate_expr (tree t)
                           ? lang_hooks.types.signed_type (type)
                           : lang_hooks.types.unsigned_type (type);
              tree temp = fold_convert (ntype, TREE_OPERAND (t, 0));
-             temp = fold (build2 (RSHIFT_EXPR, ntype, temp, op1));
+             temp = fold_build2 (RSHIFT_EXPR, ntype, temp, op1);
              return fold_convert (type, temp);
            }
        }
@@ -1140,7 +1141,7 @@ negate_expr (tree t)
       break;
     }
 
-  tem = fold (build1 (NEGATE_EXPR, TREE_TYPE (t), t));
+  tem = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
   return fold_convert (type, tem);
 }
 \f
@@ -1278,8 +1279,8 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type)
                     fold_convert (type, t2));
     }
 
-  return fold (build2 (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
@@ -1302,7 +1303,6 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
   int is_sizetype
     = (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type));
   int overflow = 0;
-  int no_overflow = 0;
 
   int1l = TREE_INT_CST_LOW (arg1);
   int1h = TREE_INT_CST_HIGH (arg1);
@@ -1331,7 +1331,6 @@ int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
         interpretation ruling is needed.  */
       lshift_double (int1l, int1h, int2l, TYPE_PRECISION (type),
                     &low, &hi, !uns);
-      no_overflow = 1;
       break;
 
     case RROTATE_EXPR:
@@ -1655,7 +1654,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 (build2 (code, type, arg0, arg1));
+  return fold_build2 (code, type, arg0, arg1);
 }
 
 /* Given two values, either both of sizetype or both of bitsizetype,
@@ -1897,7 +1896,7 @@ fold_convert (tree type, tree arg)
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (orig)
       || lang_hooks.types_compatible_p (TYPE_MAIN_VARIANT (type),
                                        TYPE_MAIN_VARIANT (orig)))
-    return fold (build1 (NOP_EXPR, type, arg));
+    return fold_build1 (NOP_EXPR, type, arg);
 
   switch (TREE_CODE (type))
     {
@@ -1912,15 +1911,15 @@ fold_convert (tree type, tree arg)
        }
       if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig)
          || TREE_CODE (orig) == OFFSET_TYPE)
-        return fold (build1 (NOP_EXPR, type, arg));
+        return fold_build1 (NOP_EXPR, type, arg);
       if (TREE_CODE (orig) == COMPLEX_TYPE)
        {
-         tem = fold (build1 (REALPART_EXPR, TREE_TYPE (orig), arg));
+         tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg);
          return fold_convert (type, tem);
        }
       gcc_assert (TREE_CODE (orig) == VECTOR_TYPE
                  && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)));
-      return fold (build1 (NOP_EXPR, type, arg));
+      return fold_build1 (NOP_EXPR, type, arg);
 
     case REAL_TYPE:
       if (TREE_CODE (arg) == INTEGER_CST)
@@ -1941,14 +1940,14 @@ fold_convert (tree type, tree arg)
        case INTEGER_TYPE: case CHAR_TYPE:
        case BOOLEAN_TYPE: case ENUMERAL_TYPE:
        case POINTER_TYPE: case REFERENCE_TYPE:
-         return fold (build1 (FLOAT_EXPR, type, arg));
+         return fold_build1 (FLOAT_EXPR, type, arg);
 
        case REAL_TYPE:
-         return fold (build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
-                              type, arg));
+         return fold_build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
+                             type, arg);
 
        case COMPLEX_TYPE:
-         tem = fold (build1 (REALPART_EXPR, TREE_TYPE (orig), arg));
+         tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg);
          return fold_convert (type, tem);
 
        default:
@@ -1973,15 +1972,15 @@ 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 (build2 (COMPLEX_EXPR, type, rpart, ipart));
+               return fold_build2 (COMPLEX_EXPR, type, rpart, ipart);
              }
 
            arg = save_expr (arg);
-           rpart = fold (build1 (REALPART_EXPR, TREE_TYPE (orig), arg));
-           ipart = fold (build1 (IMAGPART_EXPR, TREE_TYPE (orig), arg));
+           rpart = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), 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 (build2 (COMPLEX_EXPR, type, rpart, ipart));
+           return fold_build2 (COMPLEX_EXPR, type, rpart, ipart);
          }
 
        default:
@@ -1994,26 +1993,23 @@ fold_convert (tree type, tree arg)
       gcc_assert (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)));
       gcc_assert (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig)
                  || TREE_CODE (orig) == VECTOR_TYPE);
-      return fold (build1 (NOP_EXPR, type, arg));
+      return fold_build1 (NOP_EXPR, type, arg);
 
     case VOID_TYPE:
-      return fold (build1 (CONVERT_EXPR, type, fold_ignored_result (arg)));
+      return fold_build1 (CONVERT_EXPR, type, fold_ignored_result (arg));
 
     default:
       gcc_unreachable ();
     }
 }
 \f
+/* Return false if expr can be assumed not to be an value, true
+   otherwise.  */
 /* Return an expr equal to X but certainly not valid as an lvalue.  */
 
-tree
-non_lvalue (tree x)
+static bool
+maybe_lvalue_p (tree x)
 {
-  /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
-     us.  */
-  if (in_gimple_form)
-    return x;
-
   /* We only need to wrap lvalue tree codes.  */
   switch (TREE_CODE (x))
   {
@@ -2053,8 +2049,24 @@ non_lvalue (tree x)
     /* Assume the worst for front-end tree codes.  */
     if ((int)TREE_CODE (x) >= NUM_TREE_CODES)
       break;
-    return x;
+    return false;
   }
+
+  return true;
+}
+
+/* Return an expr equal to X but certainly not valid as an lvalue.  */
+
+tree
+non_lvalue (tree x)
+{
+  /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
+     us.  */
+  if (in_gimple_form)
+    return x;
+
+  if (! maybe_lvalue_p (x))
+    return x;
   return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
 }
 
@@ -2310,8 +2322,8 @@ combine_comparisons (enum tree_code code, enum tree_code lcode,
   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 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.  */
@@ -2780,16 +2792,16 @@ eval_subst (tree arg, tree old0, tree new0, tree old1, tree new1)
   switch (class)
     {
     case tcc_unary:
-      return fold (build1 (code, type,
-                          eval_subst (TREE_OPERAND (arg, 0),
-                                      old0, new0, old1, new1)));
+      return fold_build1 (code, type,
+                         eval_subst (TREE_OPERAND (arg, 0),
+                                     old0, new0, old1, new1));
 
     case tcc_binary:
-      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)));
+      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 tcc_expression:
       switch (code)
@@ -2801,13 +2813,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 (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)));
+         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;
        }
@@ -2832,7 +2844,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 (build2 (code, type, arg0, arg1));
+       return fold_build2 (code, type, arg0, arg1);
       }
 
     default:
@@ -3064,8 +3076,8 @@ distribute_bit_expr (enum tree_code code, tree type, tree arg0, tree arg1)
   else
     return 0;
 
-  return fold (build2 (TREE_CODE (arg0), type, common,
-                      fold (build2 (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
@@ -3346,8 +3358,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 (build2 (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;
@@ -3509,8 +3521,8 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
 
   if (arg0 != 0 && arg1 != 0)
     {
-      tem = fold (build2 (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;
     }
@@ -3769,11 +3781,11 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
                : TYPE_MAX_VALUE (arg0_type);
 
              if (TYPE_PRECISION (exp_type) == TYPE_PRECISION (arg0_type))
-               high_positive = fold (build2 (RSHIFT_EXPR, arg0_type,
-                                             fold_convert (arg0_type,
-                                                           high_positive),
-                                             fold_convert (arg0_type,
-                                                           integer_one_node)));
+               high_positive = fold_build2 (RSHIFT_EXPR, arg0_type,
+                                            fold_convert (arg0_type,
+                                                          high_positive),
+                                            fold_convert (arg0_type,
+                                                          integer_one_node));
 
              /* If the low bound is specified, "and" the range with the
                 range for which the original unsigned value will be
@@ -3853,13 +3865,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 (build2 (LE_EXPR, type, exp, high));
+    return fold_build2 (LE_EXPR, type, exp, high);
 
   if (high == 0)
-    return fold (build2 (GE_EXPR, type, exp, low));
+    return fold_build2 (GE_EXPR, type, exp, low);
 
   if (operand_equal_p (low, high, 0))
-    return fold (build2 (EQ_EXPR, type, exp, low));
+    return fold_build2 (EQ_EXPR, type, exp, low);
 
   if (integer_zerop (low))
     {
@@ -3898,8 +3910,8 @@ 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 (build2 (GT_EXPR, type, exp,
-                              fold_convert (etype, integer_zero_node)));
+         return fold_build2 (GT_EXPR, type, exp,
+                             fold_convert (etype, integer_zero_node));
        }
     }
 
@@ -3937,7 +3949,7 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
 
   if (value != 0 && ! TREE_OVERFLOW (value))
     return build_range_check (type,
-                             fold (build2 (MINUS_EXPR, etype, exp, low)),
+                             fold_build2 (MINUS_EXPR, etype, exp, low),
                              1, fold_convert (etype, integer_zero_node),
                              value);
 
@@ -4188,8 +4200,16 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
   if ((FLOAT_TYPE_P (TREE_TYPE (arg01))
        ? real_zerop (arg01)
        : integer_zerop (arg01))
-      && TREE_CODE (arg2) == NEGATE_EXPR
-      && operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0))
+      && ((TREE_CODE (arg2) == NEGATE_EXPR
+          && operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0))
+            /* In the case that A is of the form X-Y, '-A' (arg2) may
+               have already been folded to Y-X, check for that. */
+         || (TREE_CODE (arg1) == MINUS_EXPR
+             && TREE_CODE (arg2) == MINUS_EXPR
+             && operand_equal_p (TREE_OPERAND (arg1, 0),
+                                 TREE_OPERAND (arg2, 1), 0)
+             && operand_equal_p (TREE_OPERAND (arg1, 1),
+                                 TREE_OPERAND (arg2, 0), 0))))
     switch (comp_code)
       {
       case EQ_EXPR:
@@ -4209,7 +4229,7 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
        if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
          arg1 = fold_convert (lang_hooks.types.signed_type
                               (TREE_TYPE (arg1)), arg1);
-       tem = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
+       tem = fold_build1 (ABS_EXPR, TREE_TYPE (arg1), arg1);
        return pedantic_non_lvalue (fold_convert (type, tem));
       case UNLE_EXPR:
       case UNLT_EXPR:
@@ -4220,7 +4240,7 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
        if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
          arg1 = fold_convert (lang_hooks.types.signed_type
                               (TREE_TYPE (arg1)), arg1);
-       tem = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
+       tem = fold_build1 (ABS_EXPR, TREE_TYPE (arg1), arg1);
        return negate_expr (fold_convert (type, tem));
       default:
        gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison);
@@ -4266,7 +4286,13 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
      a number and A is not.  The conditions in the original
      expressions will be false, so all four give B.  The min()
      and max() versions would give a NaN instead.  */
-  if (operand_equal_for_comparison_p (arg01, arg2, arg00))
+  if (operand_equal_for_comparison_p (arg01, arg2, arg00)
+      /* Avoid these transformations if the COND_EXPR may be used
+        as an lvalue in the C++ front-end.  PR c++/19199.  */
+      && (in_gimple_form
+         || strcmp (lang_hooks.name, "GNU C++") != 0
+         || ! maybe_lvalue_p (arg1)
+         || ! maybe_lvalue_p (arg2)))
     {
       tree comp_op0 = arg00;
       tree comp_op1 = arg01;
@@ -4299,8 +4325,8 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
              comp_op0 = fold_convert (comp_type, comp_op0);
              comp_op1 = fold_convert (comp_type, comp_op1);
              tem = (comp_code == LE_EXPR || comp_code == UNLE_EXPR)
-                   ? fold (build2 (MIN_EXPR, comp_type, comp_op0, comp_op1))
-                   : fold (build2 (MIN_EXPR, comp_type, comp_op1, comp_op0));
+                   ? fold_build2 (MIN_EXPR, comp_type, comp_op0, comp_op1)
+                   : fold_build2 (MIN_EXPR, comp_type, comp_op1, comp_op0);
              return pedantic_non_lvalue (fold_convert (type, tem));
            }
          break;
@@ -4313,8 +4339,8 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
              comp_op0 = fold_convert (comp_type, comp_op0);
              comp_op1 = fold_convert (comp_type, comp_op1);
              tem = (comp_code == GE_EXPR || comp_code == UNGE_EXPR)
-                   ? fold (build2 (MAX_EXPR, comp_type, comp_op0, comp_op1))
-                   : fold (build2 (MAX_EXPR, comp_type, comp_op1, comp_op0));
+                   ? fold_build2 (MAX_EXPR, comp_type, comp_op0, comp_op1)
+                   : fold_build2 (MAX_EXPR, comp_type, comp_op1, comp_op0);
              return pedantic_non_lvalue (fold_convert (type, tem));
            }
          break;
@@ -4346,7 +4372,7 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
       case EQ_EXPR:
        /* We can replace A with C1 in this case.  */
        arg1 = fold_convert (type, arg01);
-       return fold (build3 (COND_EXPR, type, arg0, arg1, arg2));
+       return fold_build3 (COND_EXPR, type, arg0, arg1, arg2);
 
       case LT_EXPR:
        /* If C1 is C2 + 1, this is min(A, C2).  */
@@ -4356,8 +4382,8 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                const_binop (PLUS_EXPR, arg2,
                                             integer_one_node, 0),
                                OEP_ONLY_CONST))
-         return pedantic_non_lvalue (fold (build2 (MIN_EXPR,
-                                                   type, arg1, arg2)));
+         return pedantic_non_lvalue (fold_build2 (MIN_EXPR,
+                                                  type, arg1, arg2));
        break;
 
       case LE_EXPR:
@@ -4368,8 +4394,8 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                const_binop (MINUS_EXPR, arg2,
                                             integer_one_node, 0),
                                OEP_ONLY_CONST))
-         return pedantic_non_lvalue (fold (build2 (MIN_EXPR,
-                                                   type, arg1, arg2)));
+         return pedantic_non_lvalue (fold_build2 (MIN_EXPR,
+                                                  type, arg1, arg2));
        break;
 
       case GT_EXPR:
@@ -4380,8 +4406,8 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                const_binop (MINUS_EXPR, arg2,
                                             integer_one_node, 0),
                                OEP_ONLY_CONST))
-         return pedantic_non_lvalue (fold (build2 (MAX_EXPR,
-                                                   type, arg1, arg2)));
+         return pedantic_non_lvalue (fold_build2 (MAX_EXPR,
+                                                  type, arg1, arg2));
        break;
 
       case GE_EXPR:
@@ -4392,8 +4418,8 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
                                const_binop (PLUS_EXPR, arg2,
                                             integer_one_node, 0),
                                OEP_ONLY_CONST))
-         return pedantic_non_lvalue (fold (build2 (MAX_EXPR,
-                                                   type, arg1, arg2)));
+         return pedantic_non_lvalue (fold_build2 (MAX_EXPR,
+                                                  type, arg1, arg2));
        break;
       case NE_EXPR:
        break;
@@ -4414,14 +4440,14 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
    merge it into some range test.  Return the new tree if so.  */
 
 static tree
-fold_range_test (tree exp)
+fold_range_test (enum tree_code code, tree type, tree op0, tree op1)
 {
-  int or_op = (TREE_CODE (exp) == TRUTH_ORIF_EXPR
-              || TREE_CODE (exp) == TRUTH_OR_EXPR);
+  int or_op = (code == TRUTH_ORIF_EXPR
+              || code == TRUTH_OR_EXPR);
   int in0_p, in1_p, in_p;
   tree low0, low1, low, high0, high1, high;
-  tree lhs = make_range (TREE_OPERAND (exp, 0), &in0_p, &low0, &high0);
-  tree rhs = make_range (TREE_OPERAND (exp, 1), &in1_p, &low1, &high1);
+  tree lhs = make_range (op0, &in0_p, &low0, &high0);
+  tree rhs = make_range (op1, &in1_p, &low1, &high1);
   tree tem;
 
   /* If this is an OR operation, invert both sides; we will invert
@@ -4436,7 +4462,7 @@ fold_range_test (tree exp)
   if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0))
       && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
                       in1_p, low1, high1)
-      && 0 != (tem = (build_range_check (TREE_TYPE (exp),
+      && 0 != (tem = (build_range_check (type,
                                         lhs != 0 ? lhs
                                         : rhs != 0 ? rhs : integer_zero_node,
                                         in_p, low, high))))
@@ -4447,33 +4473,32 @@ fold_range_test (tree exp)
      is the same, make a non-short-circuit operation.  */
   else if (LOGICAL_OP_NON_SHORT_CIRCUIT
           && lhs != 0 && rhs != 0
-          && (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
-              || TREE_CODE (exp) == TRUTH_ORIF_EXPR)
+          && (code == TRUTH_ANDIF_EXPR
+              || code == TRUTH_ORIF_EXPR)
           && operand_equal_p (lhs, rhs, 0))
     {
       /* If simple enough, just rewrite.  Otherwise, make a SAVE_EXPR
         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 build2 (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
+       return build2 (code == TRUTH_ANDIF_EXPR
                       ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
-                      TREE_TYPE (exp), TREE_OPERAND (exp, 0),
-                      TREE_OPERAND (exp, 1));
+                      type, op0, op1);
 
       else if (lang_hooks.decls.global_bindings_p () == 0
               && ! CONTAINS_PLACEHOLDER_P (lhs))
        {
          tree common = save_expr (lhs);
 
-         if (0 != (lhs = build_range_check (TREE_TYPE (exp), common,
+         if (0 != (lhs = build_range_check (type, common,
                                             or_op ? ! in0_p : in0_p,
                                             low0, high0))
-             && (0 != (rhs = build_range_check (TREE_TYPE (exp), common,
+             && (0 != (rhs = build_range_check (type, common,
                                                 or_op ? ! in1_p : in1_p,
                                                 low1, high1))))
-           return build2 (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
+           return build2 (code == TRUTH_ANDIF_EXPR
                           ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
-                          TREE_TYPE (exp), lhs, rhs);
+                          type, lhs, rhs);
        }
     }
 
@@ -4782,8 +4807,8 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
       l_const = unextend (l_const, ll_bitsize, ll_unsignedp, ll_and_mask);
       l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos), 0);
       if (! integer_zerop (const_binop (BIT_AND_EXPR, l_const,
-                                       fold (build1 (BIT_NOT_EXPR,
-                                                     lntype, ll_mask)),
+                                       fold_build1 (BIT_NOT_EXPR,
+                                                    lntype, ll_mask),
                                        0)))
        {
          warning ("comparison is always %d", wanted_code == NE_EXPR);
@@ -4797,8 +4822,8 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
       r_const = unextend (r_const, rl_bitsize, rl_unsignedp, rl_and_mask);
       r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos), 0);
       if (! integer_zerop (const_binop (BIT_AND_EXPR, r_const,
-                                       fold (build1 (BIT_NOT_EXPR,
-                                                     lntype, rl_mask)),
+                                       fold_build1 (BIT_NOT_EXPR,
+                                                    lntype, rl_mask),
                                        0)))
        {
          warning ("comparison is always %d", wanted_code == NE_EXPR);
@@ -4959,12 +4984,11 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
    constant.  */
 
 static tree
-optimize_minmax_comparison (tree t)
+optimize_minmax_comparison (enum tree_code code, tree type, tree op0, tree op1)
 {
-  tree type = TREE_TYPE (t);
-  tree arg0 = TREE_OPERAND (t, 0);
+  tree arg0 = op0;
   enum tree_code op_code;
-  tree comp_const = TREE_OPERAND (t, 1);
+  tree comp_const = op1;
   tree minmax_const;
   int consts_equal, consts_lt;
   tree inner;
@@ -4983,33 +5007,42 @@ optimize_minmax_comparison (tree t)
       || TREE_CONSTANT_OVERFLOW (comp_const)
       || TREE_CODE (minmax_const) != INTEGER_CST
       || TREE_CONSTANT_OVERFLOW (minmax_const))
-    return t;
+    return NULL_TREE;
 
   /* Now handle all the various comparison codes.  We only handle EQ_EXPR
      and GT_EXPR, doing the rest with recursive calls using logical
      simplifications.  */
-  switch (TREE_CODE (t))
+  switch (code)
     {
     case NE_EXPR:  case LT_EXPR:  case LE_EXPR:
-      return
-       invert_truthvalue (optimize_minmax_comparison (invert_truthvalue (t)));
+      {
+       /* FIXME: We should be able to invert code without building a
+          scratch tree node, but doing so would require us to
+          duplicate a part of invert_truthvalue here.  */
+       tree tem = invert_truthvalue (build2 (code, type, op0, op1));
+       tem = optimize_minmax_comparison (TREE_CODE (tem),
+                                         TREE_TYPE (tem),
+                                         TREE_OPERAND (tem, 0),
+                                         TREE_OPERAND (tem, 1));
+       return invert_truthvalue (tem);
+      }
 
     case GE_EXPR:
       return
-       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))));
+       fold_build2 (TRUTH_ORIF_EXPR, type,
+                    optimize_minmax_comparison
+                    (EQ_EXPR, type, arg0, comp_const),
+                    optimize_minmax_comparison
+                    (GT_EXPR, type, arg0, comp_const));
 
     case EQ_EXPR:
       if (op_code == MAX_EXPR && consts_equal)
        /* MAX (X, 0) == 0  ->  X <= 0  */
-       return fold (build2 (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 (build2 (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  */
@@ -5017,7 +5050,7 @@ optimize_minmax_comparison (tree t)
 
       else if (consts_equal)
        /* MIN (X, 0) == 0  ->  X >= 0  */
-       return fold (build2 (GE_EXPR, type, inner, comp_const));
+       return fold_build2 (GE_EXPR, type, inner, comp_const);
 
       else if (consts_lt)
        /* MIN (X, 0) == 5  ->  false  */
@@ -5025,13 +5058,13 @@ optimize_minmax_comparison (tree t)
 
       else
        /* MIN (X, 0) == -1  ->  X == -1  */
-       return fold (build2 (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 (build2 (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  */
@@ -5044,10 +5077,10 @@ optimize_minmax_comparison (tree t)
 
       else
        /* MIN (X, 0) > -1  ->  X > -1  */
-       return fold (build2 (GT_EXPR, type, inner, comp_const));
+       return fold_build2 (GT_EXPR, type, inner, comp_const);
 
     default:
-      return t;
+      return NULL_TREE;
     }
 }
 \f
@@ -5169,7 +5202,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
           tree cstype = (*lang_hooks.types.signed_type) (ctype);
           if ((t1 = extract_muldiv (op0, c, code, cstype)) != 0)
             {
-              t1 = fold (build1 (tcode, cstype, fold_convert (cstype, t1)));
+              t1 = fold_build1 (tcode, cstype, fold_convert (cstype, t1));
               return fold_convert (ctype, t1);
             }
           break;
@@ -5177,7 +5210,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
       /* FALLTHROUGH */
     case NEGATE_EXPR:
       if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
-       return fold (build1 (tcode, ctype, fold_convert (ctype, t1)));
+       return fold_build1 (tcode, ctype, fold_convert (ctype, t1));
       break;
 
     case MIN_EXPR:  case MAX_EXPR:
@@ -5193,8 +5226,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 (build2 (tcode, ctype, fold_convert (ctype, t1),
-                              fold_convert (ctype, t2)));
+         return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
+                             fold_convert (ctype, t2));
        }
       break;
 
@@ -5235,8 +5268,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 (build2 (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.  */
@@ -5286,17 +5319,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 (build2 (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 (build2 (tcode, ctype,
-                            fold (build2 (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;
 
@@ -5318,12 +5351,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 (build2 (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 (build2 (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;
 
@@ -5333,7 +5366,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 (build2 (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
@@ -5352,15 +5385,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 (build2 (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 (build2 (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;
 
@@ -5446,14 +5479,12 @@ extract_array_ref (tree expr, tree *base, tree *offset)
    possible.  */
 
 static tree
-fold_binary_op_with_conditional_arg (tree t, enum tree_code code, tree cond,
-                                    tree arg, int cond_first_p)
+fold_binary_op_with_conditional_arg (enum tree_code code,
+                                    tree type, tree op0, tree op1,
+                                    tree cond, tree arg, int cond_first_p)
 {
-  const tree type = TREE_TYPE (t);
-  tree cond_type = cond_first_p ? TREE_TYPE (TREE_OPERAND (t, 0)) 
-                               : TREE_TYPE (TREE_OPERAND (t, 1));
-  tree arg_type = cond_first_p ? TREE_TYPE (TREE_OPERAND (t, 1)) 
-                              : TREE_TYPE (TREE_OPERAND (t, 0));
+  tree cond_type = cond_first_p ? TREE_TYPE (op0) : TREE_TYPE (op1);
+  tree arg_type = cond_first_p ? TREE_TYPE (op1) : TREE_TYPE (op0);
   tree test, true_value, false_value;
   tree lhs = NULL_TREE;
   tree rhs = NULL_TREE;
@@ -5499,7 +5530,7 @@ fold_binary_op_with_conditional_arg (tree t, enum tree_code code, tree cond,
                             : build2 (code, type, arg, false_value));
     }
 
-  test = fold (build3 (COND_EXPR, type, test, lhs, rhs));
+  test = fold_build3 (COND_EXPR, type, test, lhs, rhs);
   return fold_convert (type, test);
 }
 
@@ -5577,8 +5608,8 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
            return omit_one_operand (type, integer_one_node, arg);
 
          /* sqrt(x) > y is the same as x >= 0, if y is negative.  */
-         return fold (build2 (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)
        {
@@ -5591,8 +5622,8 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
            {
              /* sqrt(x) > y is x == +Inf, when y is very large.  */
              if (HONOR_INFINITIES (mode))
-               return fold (build2 (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.  */
@@ -5600,8 +5631,8 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
            }
 
          /* sqrt(x) > c is the same as x > c*c.  */
-         return fold (build2 (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)
        {
@@ -5620,14 +5651,14 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
              /* sqrt(x) < y is x != +Inf when y is very large and we
                 don't care about NaNs.  */
              if (! HONOR_NANS (mode))
-               return fold (build2 (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 (build2 (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
@@ -5635,32 +5666,32 @@ fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
                return NULL_TREE;
 
              arg = save_expr (arg);
-             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)))));
+             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 (build2 (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 (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)))));
+             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)));
            }
        }
     }
@@ -5711,7 +5742,7 @@ fold_inf_compare (enum tree_code code, tree type, tree arg0, tree arg1)
          && ! CONTAINS_PLACEHOLDER_P (arg0))
        {
          arg0 = save_expr (arg0);
-         return fold (build2 (EQ_EXPR, type, arg0, arg0));
+         return fold_build2 (EQ_EXPR, type, arg0, arg0);
        }
       break;
 
@@ -5719,30 +5750,30 @@ 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 (build2 (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 (build2 (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 (build2 (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));
 
       /* 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));
+      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:
       break;
@@ -5854,39 +5885,39 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
       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));
+       return fold_build2 (GE_EXPR, type, arg00, lo);
       if (TREE_OVERFLOW (lo))
-       return fold (build2 (LE_EXPR, type, arg00, hi));
+       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));
+       return fold_build2 (LT_EXPR, type, arg00, lo);
       if (TREE_OVERFLOW (lo))
-       return fold (build2 (GT_EXPR, type, arg00, hi));
+       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));
+      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));
+      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));
+      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));
+      return fold_build2 (GE_EXPR, type, arg00, lo);
 
     default:
       break;
@@ -5928,9 +5959,9 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
             == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg00))))
        {
          tree stype = lang_hooks.types.signed_type (TREE_TYPE (arg00));
-         return fold (build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
-                              result_type, fold_convert (stype, arg00),
-                              fold_convert (stype, integer_zero_node)));
+         return fold_build2 (code == EQ_EXPR ? GE_EXPR : LT_EXPR,
+                             result_type, fold_convert (stype, arg00),
+                             fold_convert (stype, integer_zero_node));
        }
 
       /* Otherwise we have (A & C) != 0 where C is a single bit,
@@ -5970,8 +6001,8 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
                        inner, size_int (bitnum));
 
       if (code == EQ_EXPR)
-       inner = fold (build2 (BIT_XOR_EXPR, intermediate_type,
-                             inner, integer_one_node));
+       inner = fold_build2 (BIT_XOR_EXPR, intermediate_type,
+                            inner, integer_one_node);
 
       /* Put the AND last so it can combine with more things.  */
       inner = build2 (BIT_AND_EXPR, intermediate_type,
@@ -6070,6 +6101,15 @@ fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
     return NULL_TREE;
   shorter_type = TREE_TYPE (arg0_unw);
 
+#ifdef HAVE_canonicalize_funcptr_for_compare
+  /* Disable this optimization if we're casting a function pointer
+     type on targets that require function pointer canonicalization.  */
+  if (HAVE_canonicalize_funcptr_for_compare
+      && TREE_CODE (shorter_type) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (shorter_type)) == FUNCTION_TYPE)
+    return NULL_TREE;
+#endif
+
   if (TYPE_PRECISION (TREE_TYPE (arg0)) <= TYPE_PRECISION (shorter_type))
     return NULL_TREE;
 
@@ -6084,8 +6124,8 @@ fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
          || (TREE_CODE (arg1_unw) == INTEGER_CST
              && TREE_CODE (shorter_type) == INTEGER_TYPE
              && int_fits_type_p (arg1_unw, shorter_type))))
-    return fold (build (code, type, arg0_unw,
-                       fold_convert (shorter_type, arg1_unw)));
+    return fold_build2 (code, type, arg0_unw,
+                      fold_convert (shorter_type, arg1_unw));
 
   if (TREE_CODE (arg1_unw) != INTEGER_CST)
     return NULL_TREE;
@@ -6144,18 +6184,29 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
   tree arg0_inner, tmp;
   tree inner_type, outer_type;
 
-  if (TREE_CODE (arg0) != NOP_EXPR)
+  if (TREE_CODE (arg0) != NOP_EXPR
+      && TREE_CODE (arg0) != CONVERT_EXPR)
     return NULL_TREE;
 
   outer_type = TREE_TYPE (arg0);
   arg0_inner = TREE_OPERAND (arg0, 0);
   inner_type = TREE_TYPE (arg0_inner);
 
+#ifdef HAVE_canonicalize_funcptr_for_compare
+  /* Disable this optimization if we're casting a function pointer
+     type on targets that require function pointer canonicalization.  */
+  if (HAVE_canonicalize_funcptr_for_compare
+      && TREE_CODE (inner_type) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE)
+    return NULL_TREE;
+#endif
+
   if (TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
     return NULL_TREE;
 
   if (TREE_CODE (arg1) != INTEGER_CST
-      && !(TREE_CODE (arg1) == NOP_EXPR
+      && !((TREE_CODE (arg1) == NOP_EXPR
+           || TREE_CODE (arg1) == CONVERT_EXPR)
           && TREE_TYPE (TREE_OPERAND (arg1, 0)) == inner_type))
     return NULL_TREE;
 
@@ -6176,7 +6227,7 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
   else
     arg1 = fold_convert (inner_type, arg1);
 
-  return fold (build (code, type, arg0_inner, arg1));
+  return fold_build2 (code, type, arg0_inner, arg1);
 }
 
 /* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
@@ -6250,9 +6301,9 @@ try_move_mult_to_index (enum tree_code code, tree addr, tree mult)
       pos = TREE_OPERAND (pos, 0);
     }
 
-  TREE_OPERAND (pos, 1) = fold (build2 (code, itype,
-                                       TREE_OPERAND (pos, 1),
-                                       delta));
+  TREE_OPERAND (pos, 1) = fold_build2 (code, itype,
+                                      TREE_OPERAND (pos, 1),
+                                      delta);
 
   return build1 (ADDR_EXPR, TREE_TYPE (addr), ret);
 }
@@ -6295,11 +6346,11 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
   if (TREE_TYPE (a1) != typea)
     return NULL_TREE;
 
-  diff = fold (build2 (MINUS_EXPR, typea, a1, a));
+  diff = fold_build2 (MINUS_EXPR, typea, a1, a);
   if (!integer_onep (diff))
     return NULL_TREE;
 
-  return fold (build2 (GE_EXPR, type, a, y));
+  return fold_build2 (GE_EXPR, type, a, y);
 }
 
 /* Fold complex addition when both components are accessible by parts.
@@ -6327,10 +6378,10 @@ fold_complex_add (tree type, tree ac, tree bc, enum tree_code code)
 
   inner_type = TREE_TYPE (type);
 
-  rr = fold (build2 (code, inner_type, ar, br));  
-  ri = fold (build2 (code, inner_type, ai, bi));  
+  rr = fold_build2 (code, inner_type, ar, br); 
+  ri = fold_build2 (code, inner_type, ai, bi); 
 
-  return fold (build2 (COMPLEX_EXPR, type, rr, ri));
+  return fold_build2 (COMPLEX_EXPR, type, rr, ri);
 }
 
 /* Perform some simplifications of complex multiplication when one or more
@@ -6403,51 +6454,51 @@ fold_complex_mult_parts (tree type, tree ar, tree ai, tree br, tree bi)
     }
   else if (ai0 && bi0)
     {
-      rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
+      rr = fold_build2 (MULT_EXPR, inner_type, ar, br);
       ri = zero;
     }
   else if (ai0 && br0)
     {
       rr = zero;
-      ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
+      ri = fold_build2 (MULT_EXPR, inner_type, ar, bi);
     }
   else if (ar0 && bi0)
     {
       rr = zero;
-      ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
+      ri = fold_build2 (MULT_EXPR, inner_type, ai, br);
     }
   else if (ar0 && br0)
     {
-      rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
-      rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
+      rr = fold_build2 (MULT_EXPR, inner_type, ai, bi);
+      rr = fold_build1 (NEGATE_EXPR, inner_type, rr);
       ri = zero;
     }
   else if (bi0)
     {
-      rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
-      ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
+      rr = fold_build2 (MULT_EXPR, inner_type, ar, br);
+      ri = fold_build2 (MULT_EXPR, inner_type, ai, br);
     }
   else if (ai0)
     {
-      rr = fold (build2 (MULT_EXPR, inner_type, ar, br));
-      ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
+      rr = fold_build2 (MULT_EXPR, inner_type, ar, br);
+      ri = fold_build2 (MULT_EXPR, inner_type, ar, bi);
     }
   else if (br0)
     {
-      rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
-      rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
-      ri = fold (build2 (MULT_EXPR, inner_type, ar, bi));
+      rr = fold_build2 (MULT_EXPR, inner_type, ai, bi);
+      rr = fold_build1 (NEGATE_EXPR, inner_type, rr);
+      ri = fold_build2 (MULT_EXPR, inner_type, ar, bi);
     }
   else if (ar0)
     {
-      rr = fold (build2 (MULT_EXPR, inner_type, ai, bi));
-      rr = fold (build1 (NEGATE_EXPR, inner_type, rr));
-      ri = fold (build2 (MULT_EXPR, inner_type, ai, br));
+      rr = fold_build2 (MULT_EXPR, inner_type, ai, bi);
+      rr = fold_build1 (NEGATE_EXPR, inner_type, rr);
+      ri = fold_build2 (MULT_EXPR, inner_type, ai, br);
     }
   else
     return NULL;
 
-  return fold (build2 (COMPLEX_EXPR, type, rr, ri));
+  return fold_build2 (COMPLEX_EXPR, type, rr, ri);
 }
 
 static tree
@@ -6538,40 +6589,40 @@ fold_complex_div_parts (tree type, tree ar, tree ai, tree br, tree bi,
 
   if (ai0 && bi0)
     {
-      rr = fold (build2 (code, inner_type, ar, br));
+      rr = fold_build2 (code, inner_type, ar, br);
       ri = zero;
     }
   else if (ai0 && br0)
     {
       rr = zero;
-      ri = fold (build2 (code, inner_type, ar, bi));
-      ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
+      ri = fold_build2 (code, inner_type, ar, bi);
+      ri = fold_build1 (NEGATE_EXPR, inner_type, ri);
     }
   else if (ar0 && bi0)
     {
       rr = zero;
-      ri = fold (build2 (code, inner_type, ai, br));
+      ri = fold_build2 (code, inner_type, ai, br);
     }
   else if (ar0 && br0)
     {
-      rr = fold (build2 (code, inner_type, ai, bi));
+      rr = fold_build2 (code, inner_type, ai, bi);
       ri = zero;
     }
   else if (bi0)
     {
-      rr = fold (build2 (code, inner_type, ar, br));
-      ri = fold (build2 (code, inner_type, ai, br));
+      rr = fold_build2 (code, inner_type, ar, br);
+      ri = fold_build2 (code, inner_type, ai, br);
     }
   else if (br0)
     {
-      rr = fold (build2 (code, inner_type, ai, bi));
-      ri = fold (build2 (code, inner_type, ar, bi));
-      ri = fold (build1 (NEGATE_EXPR, inner_type, ri));
+      rr = fold_build2 (code, inner_type, ai, bi);
+      ri = fold_build2 (code, inner_type, ar, bi);
+      ri = fold_build1 (NEGATE_EXPR, inner_type, ri);
     }
   else
     return NULL;
 
-  return fold (build2 (COMPLEX_EXPR, type, rr, ri));
+  return fold_build2 (COMPLEX_EXPR, type, rr, ri);
 }
 
 static tree
@@ -6596,25 +6647,21 @@ fold_complex_div (tree type, tree ac, tree bc, enum tree_code code)
   return fold_complex_div_parts (type, ar, ai, br, bi, code);
 }
 
-/* Fold a unary expression EXPR.  Return the folded expression if
-   folding is successful.  Otherwise, return the original
-   expression.  */
+/* Fold a unary expression of code CODE and type TYPE with operand
+   OP0.  Return the folded expression if folding is successful.
+   Otherwise, return NULL_TREE.  */
 
 static tree
-fold_unary (tree expr)
+fold_unary (enum tree_code code, tree type, tree op0)
 {
-  const tree t = expr;
-  const tree type = TREE_TYPE (expr);
   tree tem;
-  tree op0, arg0;
-  enum tree_code code = TREE_CODE (t);
+  tree arg0;
   enum tree_code_class kind = TREE_CODE_CLASS (code);
 
   gcc_assert (IS_EXPR_CODE_CLASS (kind)
              && TREE_CODE_LENGTH (code) == 1);
 
-
-  arg0 = op0 = TREE_OPERAND (t, 0);
+  arg0 = op0;
   if (arg0)
     {
       if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
@@ -6643,17 +6690,17 @@ fold_unary (tree expr)
     {
       if (TREE_CODE (arg0) == COMPOUND_EXPR)
        return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                      fold (build1 (code, type, TREE_OPERAND (arg0, 1))));
+                      fold_build1 (code, type, TREE_OPERAND (arg0, 1)));
       else if (TREE_CODE (arg0) == COND_EXPR)
        {
          tree arg01 = TREE_OPERAND (arg0, 1);
          tree arg02 = TREE_OPERAND (arg0, 2);
          if (! VOID_TYPE_P (TREE_TYPE (arg01)))
-           arg01 = fold (build1 (code, type, arg01));
+           arg01 = fold_build1 (code, type, arg01);
          if (! VOID_TYPE_P (TREE_TYPE (arg02)))
-           arg02 = fold (build1 (code, type, arg02));
-         tem = fold (build3 (COND_EXPR, type, TREE_OPERAND (arg0, 0),
-                             arg01, arg02));
+           arg02 = fold_build1 (code, type, 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
@@ -6696,11 +6743,11 @@ fold_unary (tree expr)
              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))));
+           return fold_build3 (COND_EXPR, type, arg0,
+                               fold_build1 (code, type,
+                                            integer_one_node),
+                               fold_build1 (code, type,
+                                            integer_zero_node));
        }
    }
 
@@ -6725,16 +6772,19 @@ fold_unary (tree expr)
          int inside_int = INTEGRAL_TYPE_P (inside_type);
          int inside_ptr = POINTER_TYPE_P (inside_type);
          int inside_float = FLOAT_TYPE_P (inside_type);
+         int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
          unsigned int inside_prec = TYPE_PRECISION (inside_type);
          int inside_unsignedp = TYPE_UNSIGNED (inside_type);
          int inter_int = INTEGRAL_TYPE_P (inter_type);
          int inter_ptr = POINTER_TYPE_P (inter_type);
          int inter_float = FLOAT_TYPE_P (inter_type);
+         int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
          unsigned int inter_prec = TYPE_PRECISION (inter_type);
          int inter_unsignedp = TYPE_UNSIGNED (inter_type);
          int final_int = INTEGRAL_TYPE_P (type);
          int final_ptr = POINTER_TYPE_P (type);
          int final_float = FLOAT_TYPE_P (type);
+         int final_vec = TREE_CODE (type) == VECTOR_TYPE;
          unsigned int final_prec = TYPE_PRECISION (type);
          int final_unsignedp = TYPE_UNSIGNED (type);
 
@@ -6745,7 +6795,7 @@ fold_unary (tree expr)
          if (TYPE_MAIN_VARIANT (inside_type) == TYPE_MAIN_VARIANT (type)
              && ((inter_int && final_int) || (inter_float && final_float))
              && inter_prec >= final_prec)
-           return fold (build1 (code, type, TREE_OPERAND (op0, 0)));
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
 
          /* Likewise, if the intermediate and final types are either both
             float or both integer, we don't need the middle conversion if
@@ -6754,23 +6804,27 @@ fold_unary (tree expr)
             since then we sometimes need the inner conversion.  Likewise if
             the outer has a precision not equal to the size of its mode.  */
          if ((((inter_int || inter_ptr) && (inside_int || inside_ptr))
-              || (inter_float && inside_float))
+              || (inter_float && inside_float)
+              || (inter_vec && inside_vec))
              && inter_prec >= inside_prec
-             && (inter_float || inter_unsignedp == inside_unsignedp)
+             && (inter_float || inter_vec
+                 || inter_unsignedp == inside_unsignedp)
              && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
                    && TYPE_MODE (type) == TYPE_MODE (inter_type))
-             && ! final_ptr)
-           return fold (build1 (code, type, TREE_OPERAND (op0, 0)));
+             && ! final_ptr
+             && (! final_vec || inter_prec == inside_prec))
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
 
          /* If we have a sign-extension of a zero-extended value, we can
             replace that by a single zero-extension.  */
          if (inside_int && inter_int && final_int
              && inside_prec < inter_prec && inter_prec < final_prec
              && inside_unsignedp && !inter_unsignedp)
-           return fold (build1 (code, type, TREE_OPERAND (op0, 0)));
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
 
          /* Two conversions in a row are not needed unless:
             - some conversion is floating-point (overstrict for now), or
+            - some conversion is a vector (overstrict for now), or
             - the intermediate type is narrower than both initial and
               final, or
             - the intermediate type and innermost type differ in signedness,
@@ -6780,6 +6834,7 @@ fold_unary (tree expr)
             - the final type is a pointer type and the precisions of the
               initial and intermediate types differ.  */
          if (! inside_float && ! inter_float && ! final_float
+             && ! inside_vec && ! inter_vec && ! final_vec
              && (inter_prec > inside_prec || inter_prec > final_prec)
              && ! (inside_int && inter_int
                    && inter_unsignedp != inside_unsignedp
@@ -6791,7 +6846,7 @@ fold_unary (tree expr)
              && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
                    && TYPE_MODE (type) == TYPE_MODE (inter_type))
              && ! final_ptr)
-           return fold (build1 (code, type, TREE_OPERAND (op0, 0)));
+           return fold_build1 (code, type, TREE_OPERAND (op0, 0));
        }
 
       if (TREE_CODE (op0) == MODIFY_EXPR
@@ -6802,8 +6857,7 @@ fold_unary (tree expr)
        {
          /* Don't leave an assignment inside a conversion
             unless assigning a bitfield.  */
-         tem = copy_node (t);
-         TREE_OPERAND (tem, 0) = TREE_OPERAND (op0, 1);
+         tem = build1 (code, type, TREE_OPERAND (op0, 1));
          /* First do the assignment, then return converted constant.  */
          tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, fold (tem));
          TREE_NO_WARNING (tem) = 1;
@@ -6855,8 +6909,8 @@ fold_unary (tree expr)
                                        TREE_INT_CST_HIGH (and1));
              tem = force_fit_type (tem, 0, TREE_OVERFLOW (and1),
                                    TREE_CONSTANT_OVERFLOW (and1));
-             return fold (build2 (BIT_AND_EXPR, type,
-                                  fold_convert (type, and0), tem));
+             return fold_build2 (BIT_AND_EXPR, type,
+                                 fold_convert (type, and0), tem);
            }
        }
 
@@ -6881,36 +6935,36 @@ fold_unary (tree expr)
        }
 
       tem = fold_convert_const (code, type, arg0);
-      return tem ? tem : t;
+      return tem ? tem : NULL_TREE;
 
     case VIEW_CONVERT_EXPR:
       if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
        return build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
-      return t;
+      return NULL_TREE;
 
     case NEGATE_EXPR:
       if (negate_expr_p (arg0))
        return fold_convert (type, negate_expr (arg0));
       /* Convert - (~A) to A + 1.  */
       if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == BIT_NOT_EXPR)
-       return fold (build2 (PLUS_EXPR, type, TREE_OPERAND (arg0, 0),
-                            build_int_cst (type, 1)));
-      return t;
+       return fold_build2 (PLUS_EXPR, type, TREE_OPERAND (arg0, 0),
+                           build_int_cst (type, 1));
+      return NULL_TREE;
 
     case ABS_EXPR:
       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)));
+       return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
       /* Convert fabs((double)float) into (double)fabsf(float).  */
       else if (TREE_CODE (arg0) == NOP_EXPR
               && TREE_CODE (type) == REAL_TYPE)
        {
          tree targ0 = strip_float_extensions (arg0);
          if (targ0 != arg0)
-           return fold_convert (type, fold (build1 (ABS_EXPR,
-                                                    TREE_TYPE (targ0),
-                                                    targ0)));
+           return fold_convert (type, fold_build1 (ABS_EXPR,
+                                                   TREE_TYPE (targ0),
+                                                   targ0));
        }
       else if (tree_expr_nonnegative_p (arg0))
        return arg0;
@@ -6920,9 +6974,9 @@ fold_unary (tree expr)
        {
          tem = fold_strip_sign_ops (arg0);
          if (tem)
-           return fold (build1 (ABS_EXPR, type, fold_convert (type, tem)));
+           return fold_build1 (ABS_EXPR, type, fold_convert (type, tem));
        }
-      return t;
+      return NULL_TREE;
 
     case CONJ_EXPR:
       if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
@@ -6935,14 +6989,14 @@ fold_unary (tree expr)
        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 (build2 (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;
+      return NULL_TREE;
 
     case BIT_NOT_EXPR:
       if (TREE_CODE (arg0) == INTEGER_CST)
@@ -6951,16 +7005,16 @@ fold_unary (tree expr)
        return TREE_OPERAND (arg0, 0);
       /* Convert ~ (-A) to A - 1.  */
       else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
-       return fold (build2 (MINUS_EXPR, type, TREE_OPERAND (arg0, 0),
-                            build_int_cst (type, 1)));
+       return fold_build2 (MINUS_EXPR, type, TREE_OPERAND (arg0, 0),
+                           build_int_cst (type, 1));
       /* Convert ~ (A - 1) or ~ (A + -1) to -A.  */
       else if (INTEGRAL_TYPE_P (type)
               && ((TREE_CODE (arg0) == MINUS_EXPR
                    && integer_onep (TREE_OPERAND (arg0, 1)))
                   || (TREE_CODE (arg0) == PLUS_EXPR
                       && integer_all_onesp (TREE_OPERAND (arg0, 1)))))
-       return fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0)));
-      return t;
+       return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
+      return NULL_TREE;
 
     case TRUTH_NOT_EXPR:
       /* The argument to invert_truthvalue must have Boolean type.  */
@@ -6974,24 +7028,24 @@ fold_unary (tree expr)
       tem = invert_truthvalue (arg0);
       /* Avoid infinite recursion.  */
       if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
-       return t;
+       return NULL_TREE;
       return fold_convert (type, tem);
 
     case REALPART_EXPR:
       if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
-       return t;
+       return NULL_TREE;
       else if (TREE_CODE (arg0) == COMPLEX_EXPR)
        return omit_one_operand (type, TREE_OPERAND (arg0, 0),
                                 TREE_OPERAND (arg0, 1));
       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 (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;
+       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 NULL_TREE;
 
     case IMAGPART_EXPR:
       if (TREE_CODE (TREE_TYPE (arg0)) != COMPLEX_TYPE)
@@ -7002,45 +7056,76 @@ fold_unary (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 (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;
+       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 NULL_TREE;
 
     default:
-      return t;
+      return NULL_TREE;
     } /* switch (code) */
 }
 
-/* Fold a ternary expression EXPR.  Return the folded expression if
-   folding is successful.  Otherwise, return the original
-   expression.  */
+/* Fold a binary expression of code CODE and type TYPE with operands
+   OP0 and OP1.  Return the folded expression if folding is
+   successful.  Otherwise, return NULL_TREE.  */
 
 static tree
-fold_ternary (tree expr)
+fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 {
-  const tree t = expr;
-  const tree type = TREE_TYPE (expr);
+  tree t1 = NULL_TREE;
   tree tem;
   tree arg0 = NULL_TREE, arg1 = NULL_TREE;
-  enum tree_code code = TREE_CODE (t);
   enum tree_code_class kind = TREE_CODE_CLASS (code);
-  int i;
+
+  /* WINS will be nonzero when the switch is done
+     if all operands are constant.  */
+  int wins = 1;
 
   gcc_assert (IS_EXPR_CODE_CLASS (kind)
-             && TREE_CODE_LENGTH (code) == 3);
+             && TREE_CODE_LENGTH (code) == 2);
+
+  arg0 = op0;
+  arg1 = op1;
 
-  /* For now, we iterate only twice even though we are handling
-     ternary expressions.  This is because we haven't defined arg2
-     yet.  */
-  for (i = 0; i < 2; i++)
+  if (arg0)
     {
-      tree op = TREE_OPERAND (t, i);
+      tree subop;
+
+      /* Strip any conversions that don't change the mode.  This is
+        safe for every expression, except for a comparison expression
+        because its signedness is derived from its operands.  So, in
+        the latter case, only strip conversions that don't change the
+        signedness.
+
+        Note that this is done as an internal manipulation within the
+        constant folder, in order to find the simplest representation
+        of the arguments so that their form can be studied.  In any
+        cases, the appropriate type conversions should be put back in
+        the tree that will get out of the constant folder.  */
+      if (kind == tcc_comparison)
+       STRIP_SIGN_NOPS (arg0);
+      else
+       STRIP_NOPS (arg0);
+
+      if (TREE_CODE (arg0) == COMPLEX_CST)
+       subop = TREE_REALPART (arg0);
+      else
+       subop = arg0;
+
+      if (TREE_CODE (subop) != INTEGER_CST
+         && TREE_CODE (subop) != REAL_CST)
+       /* Note that TREE_CONSTANT isn't enough:
+          static var addresses are constant but we can't
+          do arithmetic on them.  */
+       wins = 0;
+    }
 
-      if (op == 0)
-       continue;               /* Valid for CALL_EXPR, at least.  */
+  if (arg1)
+    {
+      tree subop;
 
       /* Strip any conversions that don't change the mode.  This is
         safe for every expression, except for a comparison expression
@@ -7053,448 +7138,168 @@ fold_ternary (tree expr)
         of the arguments so that their form can be studied.  In any
         cases, the appropriate type conversions should be put back in
         the tree that will get out of the constant folder.  */
-      STRIP_NOPS (op);
+      if (kind == tcc_comparison)
+       STRIP_SIGN_NOPS (arg1);
+      else
+       STRIP_NOPS (arg1);
 
-      if (i == 0)
-       arg0 = op;
-      else if (i == 1)
-       arg1 = op;
+      if (TREE_CODE (arg1) == COMPLEX_CST)
+       subop = TREE_REALPART (arg1);
+      else
+       subop = arg1;
+
+      if (TREE_CODE (subop) != INTEGER_CST
+         && TREE_CODE (subop) != REAL_CST)
+       /* Note that TREE_CONSTANT isn't enough:
+          static var addresses are constant but we can't
+          do arithmetic on them.  */
+       wins = 0;
     }
 
-  switch (code)
+  /* 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_swap_operands_p (arg0, arg1, true))
+    return fold_build2 (code, type, op1, op0);
+
+  /* Now WINS is set as described above,
+     ARG0 is the first operand of EXPR,
+     and ARG1 is the second operand (if it has more than one operand).
+
+     First check for cases where an arithmetic operation is applied to a
+     compound, conditional, or comparison operation.  Push the arithmetic
+     operation inside the compound or conditional to see if any folding
+     can then be done.  Convert comparison to conditional for this purpose.
+     The also optimizes non-constant cases that used to be done in
+     expand_expr.
+
+     Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR,
+     one of the operands is a comparison and the other is a comparison, a
+     BIT_AND_EXPR with the constant 1, or a truth value.  In that case, the
+     code below would make the expression more complex.  Change it to a
+     TRUTH_{AND,OR}_EXPR.  Likewise, convert a similar NE_EXPR to
+     TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR.  */
+
+  if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR
+       || code == EQ_EXPR || code == NE_EXPR)
+      && ((truth_value_p (TREE_CODE (arg0))
+          && (truth_value_p (TREE_CODE (arg1))
+              || (TREE_CODE (arg1) == BIT_AND_EXPR
+                  && integer_onep (TREE_OPERAND (arg1, 1)))))
+         || (truth_value_p (TREE_CODE (arg1))
+             && (truth_value_p (TREE_CODE (arg0))
+                 || (TREE_CODE (arg0) == BIT_AND_EXPR
+                     && integer_onep (TREE_OPERAND (arg0, 1)))))))
     {
-    case COMPONENT_REF:
-      if (TREE_CODE (arg0) == CONSTRUCTOR
-         && ! type_contains_placeholder_p (TREE_TYPE (arg0)))
+      tem = fold_build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
+                        : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
+                        : TRUTH_XOR_EXPR,
+                        boolean_type_node,
+                        fold_convert (boolean_type_node, arg0),
+                        fold_convert (boolean_type_node, arg1));
+
+      if (code == EQ_EXPR)
+       tem = invert_truthvalue (tem);
+
+      return fold_convert (type, tem);
+    }
+
+  if (TREE_CODE_CLASS (code) == tcc_comparison
+          && TREE_CODE (arg0) == COMPOUND_EXPR)
+    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                  fold_build2 (code, type, TREE_OPERAND (arg0, 1), arg1));
+  else if (TREE_CODE_CLASS (code) == tcc_comparison
+          && TREE_CODE (arg1) == COMPOUND_EXPR)
+    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+                  fold_build2 (code, type, arg0, TREE_OPERAND (arg1, 1)));
+  else if (TREE_CODE_CLASS (code) == tcc_binary
+          || TREE_CODE_CLASS (code) == tcc_comparison)
+    {
+      if (TREE_CODE (arg0) == COMPOUND_EXPR)
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+                      fold_build2 (code, type, TREE_OPERAND (arg0, 1),
+                                   arg1));
+      if (TREE_CODE (arg1) == COMPOUND_EXPR
+         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+                      fold_build2 (code, type,
+                                   arg0, TREE_OPERAND (arg1, 1)));
+
+      if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
        {
-         tree m = purpose_member (arg1, CONSTRUCTOR_ELTS (arg0));
-         if (m)
-           return TREE_VALUE (m);
+         tem = fold_binary_op_with_conditional_arg (code, type, op0, op1,
+                                                    arg0, arg1, 
+                                                    /*cond_first_p=*/1);
+         if (tem != NULL_TREE)
+           return tem;
        }
-      return t;
 
-    case COND_EXPR:
-      /* Pedantic ANSI C says that a conditional expression is never an lvalue,
-        so all simple results must be passed through pedantic_non_lvalue.  */
-      if (TREE_CODE (arg0) == INTEGER_CST)
+      if (TREE_CODE (arg1) == COND_EXPR || COMPARISON_CLASS_P (arg1))
        {
-         tem = TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1));
-         /* Only optimize constant conditions when the selected branch
-            has the same type as the COND_EXPR.  This avoids optimizing
-            away "c ? x : throw", where the throw has a void type.  */
-         if (! VOID_TYPE_P (TREE_TYPE (tem))
-             || VOID_TYPE_P (type))
-           return pedantic_non_lvalue (tem);
-         return t;
+         tem = fold_binary_op_with_conditional_arg (code, type, op0, op1,
+                                                    arg1, arg0, 
+                                                    /*cond_first_p=*/0);
+         if (tem != NULL_TREE)
+           return tem;
        }
-      if (operand_equal_p (arg1, TREE_OPERAND (t, 2), 0))
-       return pedantic_omit_one_operand (type, arg1, arg0);
+    }
 
-      /* If we have A op B ? A : C, we may be able to convert this to a
-        simpler expression, depending on the operation and the values
-        of B and C.  Signed zeros prevent all of these transformations,
-        for reasons given above each one.
+  switch (code)
+    {
+    case PLUS_EXPR:
+      /* A + (-B) -> A - B */
+      if (TREE_CODE (arg1) == NEGATE_EXPR)
+       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_build2 (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0));
+      /* Convert ~A + 1 to -A.  */
+      if (INTEGRAL_TYPE_P (type)
+         && TREE_CODE (arg0) == BIT_NOT_EXPR
+         && integer_onep (arg1))
+       return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
 
-         Also try swapping the arguments and inverting the conditional.  */
-      if (COMPARISON_CLASS_P (arg0)
-         && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
-                                            arg1, TREE_OPERAND (arg0, 1))
-         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
+      if (TREE_CODE (type) == COMPLEX_TYPE)
        {
-         tem = fold_cond_expr_with_comparison (type, arg0,
-                                               TREE_OPERAND (t, 1),
-                                               TREE_OPERAND (t, 2));
+         tem = fold_complex_add (type, arg0, arg1, PLUS_EXPR);
          if (tem)
            return tem;
        }
 
-      if (COMPARISON_CLASS_P (arg0)
-         && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
-                                            TREE_OPERAND (t, 2),
-                                            TREE_OPERAND (arg0, 1))
-         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 2)))))
+      if (! FLOAT_TYPE_P (type))
        {
-         tem = invert_truthvalue (arg0);
-         if (COMPARISON_CLASS_P (tem))
+         if (integer_zerop (arg1))
+           return non_lvalue (fold_convert (type, arg0));
+
+         /* If we are adding two BIT_AND_EXPR's, both of which are and'ing
+            with a constant, and the two constants have no bits in common,
+            we should treat this as a BIT_IOR_EXPR since this may produce more
+            simplifications.  */
+         if (TREE_CODE (arg0) == BIT_AND_EXPR
+             && TREE_CODE (arg1) == BIT_AND_EXPR
+             && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+             && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
+             && integer_zerop (const_binop (BIT_AND_EXPR,
+                                            TREE_OPERAND (arg0, 1),
+                                            TREE_OPERAND (arg1, 1), 0)))
            {
-             tem = fold_cond_expr_with_comparison (type, tem,
-                                                   TREE_OPERAND (t, 2),
-                                                   TREE_OPERAND (t, 1));
-             if (tem)
-               return tem;
+             code = BIT_IOR_EXPR;
+             goto bit_ior;
            }
-       }
-
-      /* If the second operand is simpler than the third, swap them
-        since that produces better jump optimization results.  */
-      if (tree_swap_operands_p (TREE_OPERAND (t, 1),
-                               TREE_OPERAND (t, 2), false))
-       {
-         /* See if this can be inverted.  If it can't, possibly because
-            it was a floating-point inequality comparison, don't do
-            anything.  */
-         tem = invert_truthvalue (arg0);
-
-         if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
-           return fold (build3 (code, type, tem,
-                                TREE_OPERAND (t, 2), TREE_OPERAND (t, 1)));
-       }
 
-      /* Convert A ? 1 : 0 to simply A.  */
-      if (integer_onep (TREE_OPERAND (t, 1))
-         && integer_zerop (TREE_OPERAND (t, 2))
-         /* If we try to convert TREE_OPERAND (t, 0) to our type, the
-            call to fold will try to move the conversion inside
-            a COND, which will recurse.  In that case, the COND_EXPR
-            is probably the best choice, so leave it alone.  */
-         && type == TREE_TYPE (arg0))
-       return pedantic_non_lvalue (arg0);
-
-      /* Convert A ? 0 : 1 to !A.  This prefers the use of NOT_EXPR
-        over COND_EXPR in cases such as floating point comparisons.  */
-      if (integer_zerop (TREE_OPERAND (t, 1))
-         && integer_onep (TREE_OPERAND (t, 2))
-         && truth_value_p (TREE_CODE (arg0)))
-       return pedantic_non_lvalue (fold_convert (type,
-                                                 invert_truthvalue (arg0)));
-
-      /* A < 0 ? <sign bit of A> : 0 is simply (A & <sign bit of A>).  */
-      if (TREE_CODE (arg0) == LT_EXPR
-          && integer_zerop (TREE_OPERAND (arg0, 1))
-          && integer_zerop (TREE_OPERAND (t, 2))
-          && (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1)))
-        return fold_convert (type, fold (build2 (BIT_AND_EXPR,
-                                                TREE_TYPE (tem), tem, arg1)));
-
-      /* (A >> N) & 1 ? (1 << N) : 0 is simply A & (1 << N).  A & 1 was
-        already handled above.  */
-      if (TREE_CODE (arg0) == BIT_AND_EXPR
-         && integer_onep (TREE_OPERAND (arg0, 1))
-         && integer_zerop (TREE_OPERAND (t, 2))
-         && integer_pow2p (arg1))
-       {
-         tree tem = TREE_OPERAND (arg0, 0);
-         STRIP_NOPS (tem);
-         if (TREE_CODE (tem) == RSHIFT_EXPR
-              && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
-              && (unsigned HOST_WIDE_INT) tree_log2 (arg1) ==
-                TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)))
-           return fold (build2 (BIT_AND_EXPR, type,
-                                TREE_OPERAND (tem, 0), arg1));
-       }
-
-      /* A & N ? N : 0 is simply A & N if N is a power of two.  This
-        is probably obsolete because the first operand should be a
-        truth value (that's why we have the two cases above), but let's
-        leave it in until we can confirm this for all front-ends.  */
-      if (integer_zerop (TREE_OPERAND (t, 2))
-         && TREE_CODE (arg0) == NE_EXPR
-         && integer_zerop (TREE_OPERAND (arg0, 1))
-         && integer_pow2p (arg1)
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR
-         && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1),
-                             arg1, OEP_ONLY_CONST))
-       return pedantic_non_lvalue (fold_convert (type,
-                                                 TREE_OPERAND (arg0, 0)));
-
-      /* Convert A ? B : 0 into A && B if A and B are truth values.  */
-      if (integer_zerop (TREE_OPERAND (t, 2))
-         && truth_value_p (TREE_CODE (arg0))
-         && truth_value_p (TREE_CODE (arg1)))
-       return 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))
-         && truth_value_p (TREE_CODE (arg0))
-         && truth_value_p (TREE_CODE (arg1)))
-       {
-         /* Only perform transformation if ARG0 is easily inverted.  */
-         tem = invert_truthvalue (arg0);
-         if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
-           return fold (build2 (TRUTH_ORIF_EXPR, type, tem, arg1));
-       }
-
-      /* Convert A ? 0 : B into !A && B if A and B are truth values.  */
-      if (integer_zerop (arg1)
-         && truth_value_p (TREE_CODE (arg0))
-         && truth_value_p (TREE_CODE (TREE_OPERAND (t, 2))))
-       {
-         /* Only perform transformation if ARG0 is easily inverted.  */
-         tem = invert_truthvalue (arg0);
-         if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
-           return fold (build2 (TRUTH_ANDIF_EXPR, type, tem,
-                                TREE_OPERAND (t, 2)));
-       }
-
-      /* Convert A ? 1 : B into A || B if A and B are truth values.  */
-      if (integer_onep (arg1)
-         && truth_value_p (TREE_CODE (arg0))
-         && truth_value_p (TREE_CODE (TREE_OPERAND (t, 2))))
-       return fold (build2 (TRUTH_ORIF_EXPR, type, arg0,
-                            TREE_OPERAND (t, 2)));
-
-      return t;
-
-    case CALL_EXPR:
-      /* Check for a built-in function.  */
-      if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
-         && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 0))
-             == FUNCTION_DECL)
-         && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
-       {
-         tree tmp = fold_builtin (t, false);
-         if (tmp)
-           return tmp;
-       }
-      return t;
-
-    default:
-      return t;
-    } /* switch (code) */
-}
-
-/* Perform constant folding and related simplification of EXPR.
-   The related simplifications include x*1 => x, x*0 => 0, etc.,
-   and application of the associative law.
-   NOP_EXPR conversions may be removed freely (as long as we
-   are careful not to change the type of the overall expression).
-   We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR,
-   but we can constant-fold them if they have constant operands.  */
-
-#ifdef ENABLE_FOLD_CHECKING
-# define fold(x) fold_1 (x)
-static tree fold_1 (tree);
-static
-#endif
-tree
-fold (tree expr)
-{
-  const tree t = expr;
-  const tree type = TREE_TYPE (expr);
-  tree t1 = NULL_TREE;
-  tree tem;
-  tree arg0 = NULL_TREE, arg1 = NULL_TREE;
-  enum tree_code code = TREE_CODE (t);
-  enum tree_code_class kind = TREE_CODE_CLASS (code);
-
-  /* WINS will be nonzero when the switch is done
-     if all operands are constant.  */
-  int wins = 1;
-
-  /* Return right away if a constant.  */
-  if (kind == tcc_constant)
-    return t;
-
-  if (IS_EXPR_CODE_CLASS (kind))
-    {
-      switch (TREE_CODE_LENGTH (code))
-       {
-       case 1:
-         return fold_unary (expr);
-       case 3:
-         return fold_ternary (expr);
-       default:
-         break;
-       }
-    }
-
-  if (IS_EXPR_CODE_CLASS (kind))
-    {
-      int len = TREE_CODE_LENGTH (code);
-      int i;
-      for (i = 0; i < len; i++)
-       {
-         tree op = TREE_OPERAND (t, i);
-         tree subop;
-
-         if (op == 0)
-           continue;           /* Valid for CALL_EXPR, at least.  */
-
-         /* Strip any conversions that don't change the mode.  This is
-            safe for every expression, except for a comparison expression
-            because its signedness is derived from its operands.  So, in
-            the latter case, only strip conversions that don't change the
-            signedness.
-
-            Note that this is done as an internal manipulation within the
-            constant folder, in order to find the simplest representation
-            of the arguments so that their form can be studied.  In any
-            cases, the appropriate type conversions should be put back in
-            the tree that will get out of the constant folder.  */
-         if (kind == tcc_comparison)
-           STRIP_SIGN_NOPS (op);
-         else
-           STRIP_NOPS (op);
-
-         if (TREE_CODE (op) == COMPLEX_CST)
-           subop = TREE_REALPART (op);
-         else
-           subop = op;
-
-         if (TREE_CODE (subop) != INTEGER_CST
-             && TREE_CODE (subop) != REAL_CST)
-           /* Note that TREE_CONSTANT isn't enough:
-              static var addresses are constant but we can't
-              do arithmetic on them.  */
-           wins = 0;
-
-         if (i == 0)
-           arg0 = op;
-         else if (i == 1)
-           arg1 = op;
-       }
-    }
-
-  /* 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_swap_operands_p (arg0, arg1, true))
-    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,
-     and ARG1 is the second operand (if it has more than one operand).
-
-     First check for cases where an arithmetic operation is applied to a
-     compound, conditional, or comparison operation.  Push the arithmetic
-     operation inside the compound or conditional to see if any folding
-     can then be done.  Convert comparison to conditional for this purpose.
-     The also optimizes non-constant cases that used to be done in
-     expand_expr.
-
-     Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR,
-     one of the operands is a comparison and the other is a comparison, a
-     BIT_AND_EXPR with the constant 1, or a truth value.  In that case, the
-     code below would make the expression more complex.  Change it to a
-     TRUTH_{AND,OR}_EXPR.  Likewise, convert a similar NE_EXPR to
-     TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR.  */
-
-  if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR
-       || code == EQ_EXPR || code == NE_EXPR)
-      && ((truth_value_p (TREE_CODE (arg0))
-          && (truth_value_p (TREE_CODE (arg1))
-              || (TREE_CODE (arg1) == BIT_AND_EXPR
-                  && integer_onep (TREE_OPERAND (arg1, 1)))))
-         || (truth_value_p (TREE_CODE (arg1))
-             && (truth_value_p (TREE_CODE (arg0))
-                 || (TREE_CODE (arg0) == BIT_AND_EXPR
-                     && integer_onep (TREE_OPERAND (arg0, 1)))))))
-    {
-      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);
-
-      return tem;
-    }
-
-  if (TREE_CODE_CLASS (code) == tcc_comparison
-          && TREE_CODE (arg0) == COMPOUND_EXPR)
-    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                  fold (build2 (code, type, TREE_OPERAND (arg0, 1), arg1)));
-  else if (TREE_CODE_CLASS (code) == tcc_comparison
-          && TREE_CODE (arg1) == COMPOUND_EXPR)
-    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
-                  fold (build2 (code, type, arg0, TREE_OPERAND (arg1, 1))));
-  else if (TREE_CODE_CLASS (code) == tcc_binary
-          || TREE_CODE_CLASS (code) == tcc_comparison)
-    {
-      if (TREE_CODE (arg0) == COMPOUND_EXPR)
-       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
-                      fold (build2 (code, type, TREE_OPERAND (arg0, 1),
-                                    arg1)));
-      if (TREE_CODE (arg1) == COMPOUND_EXPR
-         && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
-       return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
-                      fold (build2 (code, type,
-                                    arg0, TREE_OPERAND (arg1, 1))));
-
-      if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
-       {
-         tem = fold_binary_op_with_conditional_arg (t, code, arg0, arg1, 
-                                                    /*cond_first_p=*/1);
-         if (tem != NULL_TREE)
-           return tem;
-       }
-
-      if (TREE_CODE (arg1) == COND_EXPR || COMPARISON_CLASS_P (arg1))
-       {
-         tem = fold_binary_op_with_conditional_arg (t, code, arg1, arg0, 
-                                                    /*cond_first_p=*/0);
-         if (tem != NULL_TREE)
-           return tem;
-       }
-    }
-
-  switch (code)
-    {
-    case CONST_DECL:
-      return fold (DECL_INITIAL (t));
-
-    case RANGE_EXPR:
-      if (TREE_CONSTANT (t) != wins)
-       {
-         tem = copy_node (t);
-         TREE_CONSTANT (tem) = wins;
-         TREE_INVARIANT (tem) = wins;
-         return tem;
-       }
-      return t;
-
-    case PLUS_EXPR:
-      /* A + (-B) -> A - B */
-      if (TREE_CODE (arg1) == NEGATE_EXPR)
-       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 (build2 (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
-
-      if (TREE_CODE (type) == COMPLEX_TYPE)
-       {
-         tem = fold_complex_add (type, arg0, arg1, PLUS_EXPR);
-         if (tem)
-           return tem;
-       }
-
-      if (! FLOAT_TYPE_P (type))
-       {
-         if (integer_zerop (arg1))
-           return non_lvalue (fold_convert (type, arg0));
-
-         /* If we are adding two BIT_AND_EXPR's, both of which are and'ing
-            with a constant, and the two constants have no bits in common,
-            we should treat this as a BIT_IOR_EXPR since this may produce more
-            simplifications.  */
-         if (TREE_CODE (arg0) == BIT_AND_EXPR
-             && TREE_CODE (arg1) == BIT_AND_EXPR
-             && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-             && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
-             && integer_zerop (const_binop (BIT_AND_EXPR,
-                                            TREE_OPERAND (arg0, 1),
-                                            TREE_OPERAND (arg1, 1), 0)))
-           {
-             code = BIT_IOR_EXPR;
-             goto bit_ior;
-           }
-
-         /* Reassociate (plus (plus (mult) (foo)) (mult)) as
-            (plus (plus (mult) (mult)) (foo)) so that we can
-            take advantage of the factoring cases below.  */
-         if (((TREE_CODE (arg0) == PLUS_EXPR
-               || TREE_CODE (arg0) == MINUS_EXPR)
-              && TREE_CODE (arg1) == MULT_EXPR)
-             || ((TREE_CODE (arg1) == PLUS_EXPR
-                  || TREE_CODE (arg1) == MINUS_EXPR)
-                 && TREE_CODE (arg0) == MULT_EXPR))
-           {
-             tree parg0, parg1, parg, marg;
-             enum tree_code pcode;
+         /* Reassociate (plus (plus (mult) (foo)) (mult)) as
+            (plus (plus (mult) (mult)) (foo)) so that we can
+            take advantage of the factoring cases below.  */
+         if (((TREE_CODE (arg0) == PLUS_EXPR
+               || TREE_CODE (arg0) == MINUS_EXPR)
+              && TREE_CODE (arg1) == MULT_EXPR)
+             || ((TREE_CODE (arg1) == PLUS_EXPR
+                  || TREE_CODE (arg1) == MINUS_EXPR)
+                 && TREE_CODE (arg0) == MULT_EXPR))
+           {
+             tree parg0, parg1, parg, marg;
+             enum tree_code pcode;
 
              if (TREE_CODE (arg1) == MULT_EXPR)
                parg = arg0, marg = arg1;
@@ -7508,19 +7313,19 @@ fold (tree expr)
 
              if (TREE_CODE (parg0) == MULT_EXPR
                  && TREE_CODE (parg1) != MULT_EXPR)
-               return fold (build2 (pcode, type,
-                                    fold (build2 (PLUS_EXPR, type,
-                                                  fold_convert (type, parg0),
-                                                  fold_convert (type, marg))),
-                                    fold_convert (type, parg1)));
+               return fold_build2 (pcode, 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 (build2 (PLUS_EXPR, type,
-                                    fold_convert (type, parg0),
-                                    fold (build2 (pcode, type,
-                                                  fold_convert (type, marg),
-                                                  fold_convert (type,
-                                                                parg1)))));
+               return fold_build2 (PLUS_EXPR, type,
+                                   fold_convert (type, parg0),
+                                   fold_build2 (pcode, type,
+                                                fold_convert (type, marg),
+                                                fold_convert (type,
+                                                              parg1)));
            }
 
          if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
@@ -7571,20 +7376,20 @@ fold (tree expr)
 
                  if (exact_log2 (int11) > 0 && int01 % int11 == 0)
                    {
-                     alt0 = fold (build2 (MULT_EXPR, type, arg00,
-                                          build_int_cst (NULL_TREE,
-                                                         int01 / int11)));
+                     alt0 = fold_build2 (MULT_EXPR, type, arg00,
+                                         build_int_cst (NULL_TREE,
+                                                        int01 / int11));
                      alt1 = arg10;
                      same = arg11;
                    }
                }
 
              if (same)
-               return fold (build2 (MULT_EXPR, type,
-                                    fold (build2 (PLUS_EXPR, type,
-                                                  fold_convert (type, alt0),
-                                                  fold_convert (type, alt1))),
-                                    same));
+               return fold_build2 (MULT_EXPR, type,
+                                   fold_build2 (PLUS_EXPR, type,
+                                                fold_convert (type, alt0),
+                                                fold_convert (type, alt1)),
+                                   same);
            }
 
          /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
@@ -7621,16 +7426,16 @@ fold (tree expr)
            {
              tem = fold_negate_const (arg1, type);
              if (!TREE_OVERFLOW (arg1) || !flag_trapping_math)
-               return fold (build2 (MINUS_EXPR, type,
-                                    fold_convert (type, arg0),
-                                    fold_convert (type, tem)));
+               return fold_build2 (MINUS_EXPR, type,
+                                   fold_convert (type, arg0),
+                                   fold_convert (type, tem));
            }
 
          /* Convert x+x into x*2.0.  */
          if (operand_equal_p (arg0, arg1, 0)
              && SCALAR_FLOAT_TYPE_P (type))
-           return fold (build2 (MULT_EXPR, type, arg0,
-                                build_real (type, dconst2)));
+           return fold_build2 (MULT_EXPR, type, arg0,
+                               build_real (type, dconst2));
 
          /* Convert x*c+x into x*(c+1).  */
          if (flag_unsafe_math_optimizations
@@ -7643,8 +7448,8 @@ fold (tree expr)
 
              c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
              real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold (build2 (MULT_EXPR, type, arg1,
-                                  build_real (type, c)));
+             return fold_build2 (MULT_EXPR, type, arg1,
+                                 build_real (type, c));
            }
 
          /* Convert x+x*c into x*(c+1).  */
@@ -7658,8 +7463,8 @@ fold (tree expr)
 
              c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
              real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold (build2 (MULT_EXPR, type, arg0,
-                                  build_real (type, c)));
+             return fold_build2 (MULT_EXPR, type, arg0,
+                                 build_real (type, c));
            }
 
          /* Convert x*c1+x*c2 into x*(c1+c2).  */
@@ -7678,9 +7483,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 (build2 (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
@@ -7693,8 +7498,8 @@ fold (tree expr)
                  && TREE_CODE (tree10) == MULT_EXPR)
                 {
                   tree tree0;
-                  tree0 = fold (build2 (PLUS_EXPR, type, arg0, tree10));
-                  return fold (build2 (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).  */
@@ -7708,8 +7513,8 @@ fold (tree expr)
                  && TREE_CODE (tree00) == MULT_EXPR)
                 {
                   tree tree0;
-                  tree0 = fold (build2 (PLUS_EXPR, type, tree01, arg1));
-                  return fold (build2 (PLUS_EXPR, type, tree00, tree0));
+                  tree0 = fold_build2 (PLUS_EXPR, type, tree01, arg1);
+                  return fold_build2 (PLUS_EXPR, type, tree00, tree0);
                 }
             }
        }
@@ -7878,20 +7683,30 @@ fold (tree expr)
 
          return t1;
        }
-      return t;
+      return NULL_TREE;
 
     case MINUS_EXPR:
       /* A - (-B) -> A + B */
       if (TREE_CODE (arg1) == NEGATE_EXPR)
-       return fold (build2 (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 (build2 (MINUS_EXPR, type, negate_expr (arg1),
-                            TREE_OPERAND (arg0, 0)));
+       return fold_build2 (MINUS_EXPR, type, negate_expr (arg1),
+                           TREE_OPERAND (arg0, 0));
+      /* Convert -A - 1 to ~A.  */
+      if (INTEGRAL_TYPE_P (type)
+         && TREE_CODE (arg0) == NEGATE_EXPR
+         && integer_onep (arg1))
+       return fold_build1 (BIT_NOT_EXPR, type, TREE_OPERAND (arg0, 0));
+
+      /* Convert -1 - A to ~A.  */
+      if (INTEGRAL_TYPE_P (type)
+         && integer_all_onesp (arg0))
+       return fold_build1 (BIT_NOT_EXPR, type, arg1);
 
       if (TREE_CODE (type) == COMPLEX_TYPE)
        {
@@ -7912,15 +7727,15 @@ fold (tree expr)
              && TREE_CODE (arg1) == BIT_AND_EXPR)
            {
              if (operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0))
-               return fold (build2 (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 (build2 (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
@@ -7932,13 +7747,13 @@ fold (tree expr)
            {
              tree mask0 = TREE_OPERAND (arg0, 1);
              tree mask1 = TREE_OPERAND (arg1, 1);
-             tree tem = fold (build1 (BIT_NOT_EXPR, type, mask0));
+             tree tem = fold_build1 (BIT_NOT_EXPR, type, mask0);
 
              if (operand_equal_p (tem, mask1, 0))
                {
-                 tem = fold (build2 (BIT_XOR_EXPR, type,
-                                     TREE_OPERAND (arg0, 0), mask1));
-                 return fold (build2 (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);
                }
            }
        }
@@ -7970,7 +7785,7 @@ fold (tree expr)
               && (TREE_CODE (arg1) != REAL_CST
                   ||  REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
              || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
-       return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
+       return fold_build2 (PLUS_EXPR, type, arg0, negate_expr (arg1));
 
       /* Try folding difference of addresses.  */
       {
@@ -8000,19 +7815,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 (build2 (MULT_EXPR, type,
-                                fold (build2 (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 (build2 (MULT_EXPR, type,
-                                TREE_OPERAND (arg0, 0),
-                                fold (build2 (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;
@@ -8020,13 +7835,13 @@ fold (tree expr)
     case MULT_EXPR:
       /* (-A) * (-B) -> A * B  */
       if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
-       return fold (build2 (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 (build2 (MULT_EXPR, type,
-                            negate_expr (arg0),
-                            TREE_OPERAND (arg1, 0)));
+       return fold_build2 (MULT_EXPR, type,
+                           negate_expr (arg0),
+                           TREE_OPERAND (arg1, 0));
 
       if (TREE_CODE (type) == COMPLEX_TYPE)
        {
@@ -8041,19 +7856,22 @@ fold (tree expr)
            return omit_one_operand (type, arg1, arg0);
          if (integer_onep (arg1))
            return non_lvalue (fold_convert (type, arg0));
+         /* Transform x * -1 into -x.  */
+         if (integer_all_onesp (arg1))
+           return fold_convert (type, negate_expr (arg0));
 
          /* (a * (1 << b)) is (a << b)  */
          if (TREE_CODE (arg1) == LSHIFT_EXPR
              && integer_onep (TREE_OPERAND (arg1, 0)))
-           return fold (build2 (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 (build2 (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),
+             && 0 != (tem = extract_muldiv (op0,
                                             fold_convert (type, arg1),
                                             code, NULL_TREE)))
            return fold_convert (type, tem);
@@ -8088,8 +7906,8 @@ fold (tree expr)
              tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0),
                                      arg1, 0);
              if (tem)
-               return fold (build2 (RDIV_EXPR, type, tem,
-                                    TREE_OPERAND (arg0, 1)));
+               return fold_build2 (RDIV_EXPR, type, tem,
+                                   TREE_OPERAND (arg0, 1));
            }
 
           /* Strip sign operations from X in X*X, i.e. -Y*-Y -> Y*Y.  */
@@ -8099,7 +7917,7 @@ fold (tree expr)
              if (tem != NULL_TREE)
                {
                  tem = fold_convert (type, tem);
-                 return fold (build2 (MULT_EXPR, type, tem, tem));
+                 return fold_build2 (MULT_EXPR, type, tem, tem);
                }
            }
 
@@ -8123,7 +7941,7 @@ fold (tree expr)
 
                  /* Optimize root(x)*root(y) as root(x*y).  */
                  rootfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                 arg = fold (build2 (MULT_EXPR, type, arg00, arg10));
+                 arg = fold_build2 (MULT_EXPR, type, arg00, arg10);
                  arglist = build_tree_list (NULL_TREE, arg);
                  return build_function_call_expr (rootfn, arglist);
                }
@@ -8166,7 +7984,7 @@ fold (tree expr)
                  if (operand_equal_p (arg00, arg10, 0))
                    {
                      tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                     tree arg = fold (build2 (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));
@@ -8299,10 +8117,10 @@ fold (tree expr)
       if (TREE_CODE (arg0) == BIT_NOT_EXPR
          && TREE_CODE (arg1) == BIT_NOT_EXPR)
        {
-         return fold (build1 (BIT_NOT_EXPR, type,
-                              build2 (BIT_AND_EXPR, type,
-                                      TREE_OPERAND (arg0, 0),
-                                      TREE_OPERAND (arg1, 0))));
+         return fold_build1 (BIT_NOT_EXPR, type,
+                             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
@@ -8313,7 +8131,7 @@ fold (tree expr)
       if (integer_zerop (arg1))
        return non_lvalue (fold_convert (type, arg0));
       if (integer_all_onesp (arg1))
-       return fold (build1 (BIT_NOT_EXPR, type, arg0));
+       return fold_build1 (BIT_NOT_EXPR, type, arg0);
       if (operand_equal_p (arg0, arg1, 0))
        return omit_one_operand (type, integer_zero_node, arg0);
 
@@ -8398,10 +8216,10 @@ fold (tree expr)
       if (TREE_CODE (arg0) == BIT_NOT_EXPR
          && TREE_CODE (arg1) == BIT_NOT_EXPR)
        {
-         return fold (build1 (BIT_NOT_EXPR, type,
-                              build2 (BIT_IOR_EXPR, type,
-                                      TREE_OPERAND (arg0, 0),
-                                      TREE_OPERAND (arg1, 0))));
+         return fold_build1 (BIT_NOT_EXPR, type,
+                             build2 (BIT_IOR_EXPR, type,
+                                     TREE_OPERAND (arg0, 0),
+                                     TREE_OPERAND (arg1, 0)));
        }
 
       goto associate;
@@ -8412,17 +8230,17 @@ fold (tree expr)
       if (TREE_CODE (arg1) == REAL_CST
          && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1)))
          && real_zerop (arg1))
-       return t;
+       return NULL_TREE;
 
       /* (-A) / (-B) -> A / B  */
       if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
-       return fold (build2 (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 (build2 (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)))
@@ -8444,7 +8262,7 @@ fold (tree expr)
          if (flag_unsafe_math_optimizations
              && 0 != (tem = const_binop (code, build_real (type, dconst1),
                                          arg1, 0)))
-           return fold (build2 (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)
            {
@@ -8453,24 +8271,24 @@ fold (tree expr)
              if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
                {
                  tem = build_real (type, r);
-                 return fold (build2 (MULT_EXPR, type, arg0, tem));
+                 return fold_build2 (MULT_EXPR, type, arg0, tem);
                }
            }
        }
       /* Convert A/B/C to A/(B*C).  */
       if (flag_unsafe_math_optimizations
          && TREE_CODE (arg0) == RDIV_EXPR)
-       return fold (build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
-                            fold (build2 (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 (build2 (MULT_EXPR, type,
-                            fold (build2 (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
@@ -8481,8 +8299,8 @@ fold (tree expr)
          tree tem = const_binop (RDIV_EXPR, arg0,
                                  TREE_OPERAND (arg1, 1), 0);
          if (tem)
-           return fold (build2 (RDIV_EXPR, type, tem,
-                                TREE_OPERAND (arg1, 0)));
+           return fold_build2 (RDIV_EXPR, type, tem,
+                               TREE_OPERAND (arg1, 0));
        }
 
       if (TREE_CODE (type) == COMPLEX_TYPE)
@@ -8503,7 +8321,7 @@ fold (tree expr)
              tree arglist = build_tree_list (NULL_TREE,
                                              fold_convert (type, arg));
              arg1 = build_function_call_expr (expfn, arglist);
-             return fold (build2 (MULT_EXPR, type, arg0, arg1));
+             return fold_build2 (MULT_EXPR, type, arg0, arg1);
            }
 
          /* Optimize x/pow(y,z) into x*pow(y,-z).  */
@@ -8518,7 +8336,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 (build2 (MULT_EXPR, type, arg0, arg1));
+             return fold_build2 (MULT_EXPR, type, arg0, arg1);
            }
        }
 
@@ -8554,8 +8372,8 @@ fold (tree expr)
                {
                  tree tmp = TREE_OPERAND (arg0, 1);
                  tmp = build_function_call_expr (tanfn, tmp);
-                 return fold (build2 (RDIV_EXPR, type,
-                                      build_real (type, dconst1), tmp));
+                 return fold_build2 (RDIV_EXPR, type,
+                                     build_real (type, dconst1), tmp);
                }
            }
 
@@ -8593,7 +8411,7 @@ fold (tree expr)
       if (integer_onep (arg1))
        return non_lvalue (fold_convert (type, arg0));
       if (integer_zerop (arg1))
-       return t;
+       return NULL_TREE;
       /* X / -1 is -X.  */
       if (!TYPE_UNSIGNED (type)
          && TREE_CODE (arg1) == INTEGER_CST
@@ -8609,11 +8427,10 @@ 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 (build2 (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,
-                                        code, NULL_TREE)))
+         && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
        return fold_convert (type, tem);
 
       if (TREE_CODE (type) == COMPLEX_TYPE)
@@ -8636,7 +8453,7 @@ fold (tree expr)
       /* X % 0, return X % 0 unchanged so that we can get the
         proper warnings and errors.  */
       if (integer_zerop (arg1))
-       return t;
+       return NULL_TREE;
 
       /* 0 % X is always zero, but be sure to preserve any side
         effects in X.  Place this after checking for X == 0.  */
@@ -8674,8 +8491,8 @@ fold (tree expr)
            }
 
          mask = build_int_cst_wide (type, low, high);
-         return fold (build2 (BIT_AND_EXPR, type,
-                              fold_convert (type, arg0), mask));
+         return fold_build2 (BIT_AND_EXPR, type,
+                             fold_convert (type, arg0), mask);
        }
 
       /* X % -C is the same as X % C.  */
@@ -8686,20 +8503,19 @@ fold (tree expr)
          && !flag_trapv
          /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
          && !sign_bit_p (arg1, arg1))
-       return fold (build2 (code, type, fold_convert (type, arg0),
-                            fold_convert (type, negate_expr (arg1))));
+       return fold_build2 (code, type, fold_convert (type, arg0),
+                           fold_convert (type, negate_expr (arg1)));
 
       /* X % -Y is the same as X % Y.  */
       if (code == TRUNC_MOD_EXPR
          && !TYPE_UNSIGNED (type)
          && TREE_CODE (arg1) == NEGATE_EXPR
          && !flag_trapv)
-       return fold (build2 (code, type, fold_convert (type, arg0),
-                            fold_convert (type, TREE_OPERAND (arg1, 0))));
+       return fold_build2 (code, type, fold_convert (type, arg0),
+                           fold_convert (type, TREE_OPERAND (arg1, 0)));
 
       if (TREE_CODE (arg1) == INTEGER_CST
-         && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
-                                        code, NULL_TREE)))
+         && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
        return fold_convert (type, tem);
 
       goto binary;
@@ -8726,7 +8542,7 @@ fold (tree expr)
       /* Since negative shift count is not well-defined,
         don't try to compute it in the compiler.  */
       if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
-       return t;
+       return NULL_TREE;
       /* Rewrite an LROTATE_EXPR by a constant into an
         RROTATE_EXPR by a new constant.  */
       if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
@@ -8735,7 +8551,7 @@ fold (tree expr)
                                    GET_MODE_BITSIZE (TYPE_MODE (type)));
          tem = fold_convert (TREE_TYPE (arg1), tem);
          tem = const_binop (MINUS_EXPR, tem, arg1, 0);
-         return fold (build2 (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
@@ -8746,11 +8562,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 (build2 (TREE_CODE (arg0), type,
-                            fold (build2 (code, type,
-                                          TREE_OPERAND (arg0, 0), arg1)),
-                            fold (build2 (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.  */
@@ -8825,17 +8641,17 @@ fold (tree expr)
        {
          tem = fold_to_nonsharp_ineq_using_bound (arg0, arg1);
          if (tem)
-           return fold (build2 (code, type, tem, arg1));
+           return fold_build2 (code, type, tem, arg1);
 
          tem = fold_to_nonsharp_ineq_using_bound (arg1, arg0);
          if (tem)
-           return fold (build2 (code, type, arg0, tem));
+           return fold_build2 (code, type, arg0, tem);
        }
 
     truth_andor:
       /* We only do these simplifications if we are optimizing.  */
       if (!optimize)
-       return t;
+       return NULL_TREE;
 
       /* Check for things like (A || B) && (A || C).  We can convert this
         to A || (B && C).  Note that either operator can be any of the four
@@ -8860,27 +8676,27 @@ fold (tree expr)
                                 || code == TRUTH_OR_EXPR));
 
          if (operand_equal_p (a00, a10, 0))
-           return fold (build2 (TREE_CODE (arg0), type, a00,
-                                fold (build2 (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 (build2 (TREE_CODE (arg0), type, a00,
-                                fold (build2 (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 (build2 (TREE_CODE (arg0), type, a01,
-                                fold (build2 (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 (build2 (TREE_CODE (arg0), type,
-                                fold (build2 (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.  */
-      if (0 != (tem = fold_range_test (t)))
+      if (0 != (tem = fold_range_test (code, type, op0, op1)))
        return tem;
 
       /* Check for the possibility of merging component references.  If our
@@ -8889,12 +8705,12 @@ fold (tree expr)
       if (TREE_CODE (arg0) == code
          && 0 != (tem = fold_truthop (code, type,
                                       TREE_OPERAND (arg0, 1), arg1)))
-       return fold (build2 (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;
 
-      return t;
+      return NULL_TREE;
 
     case TRUTH_ORIF_EXPR:
       /* Note that the operands of this must be ints
@@ -8937,7 +8753,14 @@ fold (tree expr)
        return non_lvalue (fold_convert (type, arg0));
       /* If the second arg is constant true, this is a logical inversion.  */
       if (integer_onep (arg1))
-       return non_lvalue (fold_convert (type, invert_truthvalue (arg0)));
+       {
+         /* Only call invert_truthvalue if operand is a truth value.  */
+         if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
+           tem = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg0), arg0);
+         else
+           tem = invert_truthvalue (arg0);
+         return non_lvalue (fold_convert (type, tem));
+       }
       /* Identical arguments cancel to zero.  */
       if (operand_equal_p (arg0, arg1, 0))
        return omit_one_operand (type, integer_zero_node, arg0);
@@ -8952,7 +8775,7 @@ fold (tree expr)
          && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
        return omit_one_operand (type, integer_one_node, arg0);
 
-      return t;
+      return NULL_TREE;
 
     case EQ_EXPR:
     case NE_EXPR:
@@ -8962,7 +8785,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 (build2 (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.  */
@@ -8996,7 +8819,7 @@ fold (tree expr)
       /* If this is a comparison of two exprs that look like an
         ARRAY_REF of the same object, then we can fold this to a
         comparison of the two offsets.  */
-      if (COMPARISON_CLASS_P (t))
+      if (TREE_CODE_CLASS (code) == tcc_comparison)
        {
          tree base0, offset0, base1, offset1;
 
@@ -9016,7 +8839,7 @@ fold (tree expr)
                offset1 = build_int_cst (TREE_TYPE (offset0), 0);
 
              if (TREE_TYPE (offset0) == TREE_TYPE (offset1))
-               return fold (build2 (code, type, offset0, offset1));
+               return fold_build2 (code, type, offset0, offset1);
            }
        }
 
@@ -9031,14 +8854,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 (build2 (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 (build2 (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)
          {
@@ -9048,16 +8871,16 @@ fold (tree expr)
            /* (-a) CMP CST -> a swap(CMP) (-CST)  */
            if (TREE_CODE (arg0) == NEGATE_EXPR)
              return
-               fold (build2 (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 (build2 (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)
@@ -9089,7 +8912,7 @@ fold (tree expr)
                                          ? MINUS_EXPR : PLUS_EXPR,
                                          arg1, TREE_OPERAND (arg0, 1), 0))
              && ! TREE_CONSTANT_OVERFLOW (tem))
-           return fold (build2 (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.
@@ -9101,8 +8924,8 @@ fold (tree expr)
              && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
                                          arg1, 0))
              && ! TREE_CONSTANT_OVERFLOW (tem))
-           return fold (build2 (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
@@ -9136,16 +8959,16 @@ fold (tree expr)
 
          if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
            {
-             newconst = fold (build2 (PLUS_EXPR, TREE_TYPE (arg0),
-                                      arg1, TREE_OPERAND (arg0, 1)));
+             newconst = fold_build2 (PLUS_EXPR, TREE_TYPE (arg0),
+                                     arg1, TREE_OPERAND (arg0, 1));
              varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0),
                              TREE_OPERAND (arg0, 0),
                              TREE_OPERAND (arg0, 1));
            }
          else
            {
-             newconst = fold (build2 (MINUS_EXPR, TREE_TYPE (arg0),
-                                      arg1, TREE_OPERAND (arg0, 1)));
+             newconst = fold_build2 (MINUS_EXPR, TREE_TYPE (arg0),
+                                     arg1, TREE_OPERAND (arg0, 1));
              varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0),
                              TREE_OPERAND (arg0, 0),
                              TREE_OPERAND (arg0, 1));
@@ -9166,8 +8989,8 @@ fold (tree expr)
              /* First check whether the comparison would come out
                 always the same.  If we don't do that we would
                 change the meaning with the masking.  */
-             folded_compare = fold (build2 (code, type,
-                                            TREE_OPERAND (varop, 0), arg1));
+             folded_compare = fold_build2 (code, type,
+                                           TREE_OPERAND (varop, 0), arg1);
              if (integer_zerop (folded_compare)
                  || integer_onep (folded_compare))
                return omit_one_operand (type, folded_compare, varop);
@@ -9175,13 +8998,13 @@ fold (tree expr)
              shift = build_int_cst (NULL_TREE,
                                     TYPE_PRECISION (TREE_TYPE (varop)) - size);
              shift = fold_convert (TREE_TYPE (varop), shift);
-             newconst = fold (build2 (LSHIFT_EXPR, TREE_TYPE (varop),
-                                      newconst, shift));
-             newconst = fold (build2 (RSHIFT_EXPR, TREE_TYPE (varop),
-                                      newconst, shift));
+             newconst = fold_build2 (LSHIFT_EXPR, TREE_TYPE (varop),
+                                     newconst, shift);
+             newconst = fold_build2 (RSHIFT_EXPR, TREE_TYPE (varop),
+                                     newconst, shift);
            }
 
-         return fold (build2 (code, type, varop, newconst));
+         return fold_build2 (code, type, varop, newconst);
        }
 
       /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
@@ -9195,11 +9018,11 @@ fold (tree expr)
            {
            case GE_EXPR:
              arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-             return fold (build2 (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 (build2 (LE_EXPR, type, arg0, arg1));
+             return fold_build2 (LE_EXPR, type, arg0, arg1);
 
            default:
              break;
@@ -9273,13 +9096,13 @@ fold (tree expr)
                  return omit_one_operand (type, integer_zero_node, arg0);
 
                case GE_EXPR:
-                 return fold (build2 (EQ_EXPR, type, arg0, arg1));
+                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
 
                case LE_EXPR:
                  return omit_one_operand (type, integer_one_node, arg0);
 
                case LT_EXPR:
-                 return fold (build2 (NE_EXPR, type, arg0, arg1));
+                 return fold_build2 (NE_EXPR, type, arg0, arg1);
 
                /* The GE_EXPR and LT_EXPR cases above are not normally
                   reached because of previous transformations.  */
@@ -9294,10 +9117,10 @@ fold (tree expr)
                {
                case GT_EXPR:
                  arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
-                 return fold (build2 (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 (build2 (NE_EXPR, type, arg0, arg1));
+                 return fold_build2 (NE_EXPR, type, arg0, arg1);
                default:
                  break;
                }
@@ -9310,13 +9133,13 @@ fold (tree expr)
                  return omit_one_operand (type, integer_zero_node, arg0);
 
                case LE_EXPR:
-                 return fold (build2 (EQ_EXPR, type, arg0, arg1));
+                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
 
                case GE_EXPR:
                  return omit_one_operand (type, integer_one_node, arg0);
 
                case GT_EXPR:
-                 return fold (build2 (NE_EXPR, type, arg0, arg1));
+                 return fold_build2 (NE_EXPR, type, arg0, arg1);
 
                default:
                  break;
@@ -9328,10 +9151,10 @@ fold (tree expr)
                {
                case GE_EXPR:
                  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold (build2 (NE_EXPR, type, arg0, arg1));
+                 return fold_build2 (NE_EXPR, type, arg0, arg1);
                case LT_EXPR:
                  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-                 return fold (build2 (EQ_EXPR, type, arg0, arg1));
+                 return fold_build2 (EQ_EXPR, type, arg0, arg1);
                default:
                  break;
                }
@@ -9371,7 +9194,7 @@ fold (tree expr)
                                      ? MINUS_EXPR : PLUS_EXPR,
                                      arg1, TREE_OPERAND (arg0, 1), 0))
          && ! TREE_CONSTANT_OVERFLOW (tem))
-       return fold (build2 (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)
@@ -9380,17 +9203,18 @@ fold (tree expr)
               && 0 != (tem = negate_expr (arg1))
               && TREE_CODE (tem) == INTEGER_CST
               && ! TREE_CONSTANT_OVERFLOW (tem))
-       return fold (build2 (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 (build2 (code, type,
-                            TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)));
+       return fold_build2 (code, type,
+                           TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
 
       else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
-              && TREE_CODE (arg0) == NOP_EXPR)
+              && (TREE_CODE (arg0) == NOP_EXPR
+                  || TREE_CODE (arg0) == CONVERT_EXPR))
        {
          /* If we are widening one operand of an integer comparison,
             see if the other operand is similarly being widened.  Perhaps we
@@ -9411,7 +9235,13 @@ fold (tree expr)
               && (TREE_CODE (arg0) == MIN_EXPR
                   || TREE_CODE (arg0) == MAX_EXPR)
               && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       return optimize_minmax_comparison (t);
+       {
+         tem = optimize_minmax_comparison (code, type, op0, op1);
+         if (tem)
+           return tem;
+
+         return NULL_TREE;
+       }
 
       /* If we are comparing an ABS_EXPR with a constant, we can
         convert all the cases into explicit comparisons, but they may
@@ -9424,11 +9254,11 @@ fold (tree expr)
               && (0 != (tem = negate_expr (arg1)))
               && TREE_CODE (tem) == INTEGER_CST
               && ! TREE_CONSTANT_OVERFLOW (tem))
-       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)));
+       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));
 
       /* Convert ABS_EXPR<x> >= 0 to true.  */
       else if (code == GE_EXPR
@@ -9448,7 +9278,7 @@ fold (tree expr)
       else if ((code == EQ_EXPR || code == NE_EXPR)
               && TREE_CODE (arg0) == ABS_EXPR
               && (integer_zerop (arg1) || real_zerop (arg1)))
-       return fold (build2 (code, type, TREE_OPERAND (arg0, 0), arg1));
+       return fold_build2 (code, 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
@@ -9463,23 +9293,23 @@ fold (tree expr)
          if (TREE_CODE (arg00) == LSHIFT_EXPR
              && integer_onep (TREE_OPERAND (arg00, 0)))
            return
-             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));
+             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 (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));
+             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
@@ -9495,14 +9325,14 @@ fold (tree expr)
          && integer_pow2p (TREE_OPERAND (arg0, 1)))
        {
          tree newtype = lang_hooks.types.unsigned_type (TREE_TYPE (arg0));
-         tree newmod = fold (build2 (TREE_CODE (arg0), newtype,
-                                     fold_convert (newtype,
-                                                   TREE_OPERAND (arg0, 0)),
-                                     fold_convert (newtype,
-                                                   TREE_OPERAND (arg0, 1))));
+         tree newmod = fold_build2 (TREE_CODE (arg0), newtype,
+                                    fold_convert (newtype,
+                                                  TREE_OPERAND (arg0, 0)),
+                                    fold_convert (newtype,
+                                                  TREE_OPERAND (arg0, 1)));
 
-         return fold (build2 (code, type, newmod,
-                              fold_convert (newtype, arg1)));
+         return fold_build2 (code, type, newmod,
+                             fold_convert (newtype, arg1));
        }
 
       /* If this is an NE comparison of zero with an AND of one, remove the
@@ -9518,9 +9348,9 @@ 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 (build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
-                            arg0, fold_convert (TREE_TYPE (arg0),
-                                                integer_zero_node)));
+       return fold_build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
+                           arg0, fold_convert (TREE_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.  */
@@ -9535,11 +9365,11 @@ fold (tree expr)
          && TREE_CODE (arg1) == INTEGER_CST
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
        {
-         tree notc = fold (build1 (BIT_NOT_EXPR,
-                                   TREE_TYPE (TREE_OPERAND (arg0, 1)),
-                                   TREE_OPERAND (arg0, 1)));
-         tree dandnotc = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
-                                       arg1, notc));
+         tree notc = fold_build1 (BIT_NOT_EXPR,
+                                  TREE_TYPE (TREE_OPERAND (arg0, 1)),
+                                  TREE_OPERAND (arg0, 1));
+         tree dandnotc = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                                      arg1, notc);
          tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
          if (integer_nonzerop (dandnotc))
            return omit_one_operand (type, rslt, arg0);
@@ -9552,9 +9382,9 @@ fold (tree expr)
          && TREE_CODE (arg1) == INTEGER_CST
          && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
        {
-         tree notd = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1));
-         tree candnotd = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
-                                       TREE_OPERAND (arg0, 1), notd));
+         tree notd = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1);
+         tree candnotd = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+                                      TREE_OPERAND (arg0, 1), notd);
          tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
          if (integer_nonzerop (candnotd))
            return omit_one_operand (type, rslt, arg0);
@@ -9602,7 +9432,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 (build2 (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
@@ -9656,20 +9486,20 @@ fold (tree expr)
                 was the same as ARG1.  */
 
              tree high_result
-               = fold (build2 (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 (build2 (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 (build2 (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
@@ -9753,16 +9583,16 @@ fold (tree expr)
 
          arg0 = save_expr (arg0);
          arg1 = save_expr (arg1);
-         real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
-         imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
-         real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
-         imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
+         real0 = fold_build1 (REALPART_EXPR, subtype, arg0);
+         imag0 = fold_build1 (IMAGPART_EXPR, subtype, arg0);
+         real1 = fold_build1 (REALPART_EXPR, subtype, arg1);
+         imag1 = fold_build1 (IMAGPART_EXPR, subtype, arg1);
 
-         return fold (build2 ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
-                               : TRUTH_ORIF_EXPR),
-                              type,
-                              fold (build2 (code, type, real0, real1)),
-                              fold (build2 (code, type, imag0, imag1))));
+         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
@@ -9784,11 +9614,11 @@ fold (tree expr)
              && (arglist = TREE_OPERAND (arg0, 1))
              && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
              && ! TREE_CHAIN (arglist))
-           return fold (build2 (code, type,
-                                build1 (INDIRECT_REF, char_type_node,
-                                        TREE_VALUE (arglist)),
-                                fold_convert (char_type_node,
-                                              integer_zero_node)));
+           return fold_build2 (code, type,
+                               build1 (INDIRECT_REF, char_type_node,
+                                       TREE_VALUE (arglist)),
+                               fold_convert (char_type_node,
+                                             integer_zero_node));
        }
 
       /* We can fold X/C1 op C2 where C1 and C2 are integer constants
@@ -9813,7 +9643,7 @@ fold (tree expr)
        return constant_boolean_node (code==NE_EXPR, type);
 
       t1 = fold_relational_const (code, type, arg0, arg1);
-      return t1 == NULL_TREE ? t : t1;
+      return t1 == NULL_TREE ? NULL_TREE : t1;
 
     case UNORDERED_EXPR:
     case ORDERED_EXPR:
@@ -9872,17 +9702,17 @@ fold (tree expr)
          newtype = TREE_TYPE (targ1);
 
        if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
-         return fold (build2 (code, type, fold_convert (newtype, targ0),
-                              fold_convert (newtype, targ1)));
+         return fold_build2 (code, type, fold_convert (newtype, targ0),
+                             fold_convert (newtype, targ1));
       }
 
-      return t;
+      return NULL_TREE;
 
     case COMPOUND_EXPR:
       /* When pedantic, a compound expression can be neither an lvalue
         nor an integer constant expression.  */
       if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
-       return t;
+       return NULL_TREE;
       /* Don't let (0, 0) be null pointer constant.  */
       tem = integer_zerop (arg1) ? build1 (NOP_EXPR, type, arg1)
                                 : fold_convert (type, arg1);
@@ -9891,7 +9721,290 @@ fold (tree expr)
     case COMPLEX_EXPR:
       if (wins)
        return build_complex (type, arg0, arg1);
-      return t;
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    } /* switch (code) */
+}
+
+/* Fold a ternary expression of code CODE and type TYPE with operands
+   OP0, OP1, and OP2.  Return the folded expression if folding is
+   successful.  Otherwise, return NULL_TREE.  */
+
+static tree
+fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
+{
+  tree tem;
+  tree arg0 = NULL_TREE, arg1 = NULL_TREE;
+  enum tree_code_class kind = TREE_CODE_CLASS (code);
+
+  gcc_assert (IS_EXPR_CODE_CLASS (kind)
+             && TREE_CODE_LENGTH (code) == 3);
+
+  /* Strip any conversions that don't change the mode.  This is safe
+     for every expression, except for a comparison expression because
+     its signedness is derived from its operands.  So, in the latter
+     case, only strip conversions that don't change the signedness.
+
+     Note that this is done as an internal manipulation within the
+     constant folder, in order to find the simplest representation of
+     the arguments so that their form can be studied.  In any cases,
+     the appropriate type conversions should be put back in the tree
+     that will get out of the constant folder.  */
+  if (op0)
+    {
+      arg0 = op0;
+      STRIP_NOPS (arg0);
+    }
+
+  if (op1)
+    {
+      arg1 = op1;
+      STRIP_NOPS (arg1);
+    }
+
+  switch (code)
+    {
+    case COMPONENT_REF:
+      if (TREE_CODE (arg0) == CONSTRUCTOR
+         && ! type_contains_placeholder_p (TREE_TYPE (arg0)))
+       {
+         tree m = purpose_member (arg1, CONSTRUCTOR_ELTS (arg0));
+         if (m)
+           return TREE_VALUE (m);
+       }
+      return NULL_TREE;
+
+    case COND_EXPR:
+      /* Pedantic ANSI C says that a conditional expression is never an lvalue,
+        so all simple results must be passed through pedantic_non_lvalue.  */
+      if (TREE_CODE (arg0) == INTEGER_CST)
+       {
+         tem = integer_zerop (arg0) ? op2 : op1;
+         /* Only optimize constant conditions when the selected branch
+            has the same type as the COND_EXPR.  This avoids optimizing
+            away "c ? x : throw", where the throw has a void type.  */
+         if (! VOID_TYPE_P (TREE_TYPE (tem))
+             || VOID_TYPE_P (type))
+           return pedantic_non_lvalue (tem);
+         return NULL_TREE;
+       }
+      if (operand_equal_p (arg1, op2, 0))
+       return pedantic_omit_one_operand (type, arg1, arg0);
+
+      /* If we have A op B ? A : C, we may be able to convert this to a
+        simpler expression, depending on the operation and the values
+        of B and C.  Signed zeros prevent all of these transformations,
+        for reasons given above each one.
+
+         Also try swapping the arguments and inverting the conditional.  */
+      if (COMPARISON_CLASS_P (arg0)
+         && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
+                                            arg1, TREE_OPERAND (arg0, 1))
+         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
+       {
+         tem = fold_cond_expr_with_comparison (type, arg0, op1, op2);
+         if (tem)
+           return tem;
+       }
+
+      if (COMPARISON_CLASS_P (arg0)
+         && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
+                                            op2,
+                                            TREE_OPERAND (arg0, 1))
+         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2))))
+       {
+         tem = invert_truthvalue (arg0);
+         if (COMPARISON_CLASS_P (tem))
+           {
+             tem = fold_cond_expr_with_comparison (type, tem, op2, op1);
+             if (tem)
+               return tem;
+           }
+       }
+
+      /* If the second operand is simpler than the third, swap them
+        since that produces better jump optimization results.  */
+      if (tree_swap_operands_p (op1, op2, false))
+       {
+         /* See if this can be inverted.  If it can't, possibly because
+            it was a floating-point inequality comparison, don't do
+            anything.  */
+         tem = invert_truthvalue (arg0);
+
+         if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
+           return fold_build3 (code, type, tem, op2, op1);
+       }
+
+      /* Convert A ? 1 : 0 to simply A.  */
+      if (integer_onep (op1)
+         && integer_zerop (op2)
+         /* If we try to convert OP0 to our type, the
+            call to fold will try to move the conversion inside
+            a COND, which will recurse.  In that case, the COND_EXPR
+            is probably the best choice, so leave it alone.  */
+         && type == TREE_TYPE (arg0))
+       return pedantic_non_lvalue (arg0);
+
+      /* Convert A ? 0 : 1 to !A.  This prefers the use of NOT_EXPR
+        over COND_EXPR in cases such as floating point comparisons.  */
+      if (integer_zerop (op1)
+         && integer_onep (op2)
+         && truth_value_p (TREE_CODE (arg0)))
+       return pedantic_non_lvalue (fold_convert (type,
+                                                 invert_truthvalue (arg0)));
+
+      /* A < 0 ? <sign bit of A> : 0 is simply (A & <sign bit of A>).  */
+      if (TREE_CODE (arg0) == LT_EXPR
+          && integer_zerop (TREE_OPERAND (arg0, 1))
+          && integer_zerop (op2)
+          && (tem = sign_bit_p (TREE_OPERAND (arg0, 0), arg1)))
+        return fold_convert (type, fold_build2 (BIT_AND_EXPR,
+                                               TREE_TYPE (tem), tem, arg1));
+
+      /* (A >> N) & 1 ? (1 << N) : 0 is simply A & (1 << N).  A & 1 was
+        already handled above.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+         && integer_onep (TREE_OPERAND (arg0, 1))
+         && integer_zerop (op2)
+         && integer_pow2p (arg1))
+       {
+         tree tem = TREE_OPERAND (arg0, 0);
+         STRIP_NOPS (tem);
+         if (TREE_CODE (tem) == RSHIFT_EXPR
+              && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
+              && (unsigned HOST_WIDE_INT) tree_log2 (arg1) ==
+                TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)))
+           return fold_build2 (BIT_AND_EXPR, type,
+                               TREE_OPERAND (tem, 0), arg1);
+       }
+
+      /* A & N ? N : 0 is simply A & N if N is a power of two.  This
+        is probably obsolete because the first operand should be a
+        truth value (that's why we have the two cases above), but let's
+        leave it in until we can confirm this for all front-ends.  */
+      if (integer_zerop (op2)
+         && TREE_CODE (arg0) == NE_EXPR
+         && integer_zerop (TREE_OPERAND (arg0, 1))
+         && integer_pow2p (arg1)
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR
+         && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1),
+                             arg1, OEP_ONLY_CONST))
+       return pedantic_non_lvalue (fold_convert (type,
+                                                 TREE_OPERAND (arg0, 0)));
+
+      /* Convert A ? B : 0 into A && B if A and B are truth values.  */
+      if (integer_zerop (op2)
+         && truth_value_p (TREE_CODE (arg0))
+         && truth_value_p (TREE_CODE (arg1)))
+       return 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 (op2)
+         && truth_value_p (TREE_CODE (arg0))
+         && truth_value_p (TREE_CODE (arg1)))
+       {
+         /* Only perform transformation if ARG0 is easily inverted.  */
+         tem = invert_truthvalue (arg0);
+         if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
+           return fold_build2 (TRUTH_ORIF_EXPR, type, tem, arg1);
+       }
+
+      /* Convert A ? 0 : B into !A && B if A and B are truth values.  */
+      if (integer_zerop (arg1)
+         && truth_value_p (TREE_CODE (arg0))
+         && truth_value_p (TREE_CODE (op2)))
+       {
+         /* Only perform transformation if ARG0 is easily inverted.  */
+         tem = invert_truthvalue (arg0);
+         if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
+           return fold_build2 (TRUTH_ANDIF_EXPR, type, tem, op2);
+       }
+
+      /* Convert A ? 1 : B into A || B if A and B are truth values.  */
+      if (integer_onep (arg1)
+         && truth_value_p (TREE_CODE (arg0))
+         && truth_value_p (TREE_CODE (op2)))
+       return fold_build2 (TRUTH_ORIF_EXPR, type, arg0, op2);
+
+      return NULL_TREE;
+
+    case CALL_EXPR:
+      /* Check for a built-in function.  */
+      if (TREE_CODE (op0) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (op0, 0)) == FUNCTION_DECL
+         && DECL_BUILT_IN (TREE_OPERAND (op0, 0)))
+       {
+         tree fndecl = TREE_OPERAND (op0, 0);
+         tree arglist = op1;
+         tree tmp = fold_builtin (fndecl, arglist, false);
+         if (tmp)
+           return tmp;
+       }
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    } /* switch (code) */
+}
+
+/* Perform constant folding and related simplification of EXPR.
+   The related simplifications include x*1 => x, x*0 => 0, etc.,
+   and application of the associative law.
+   NOP_EXPR conversions may be removed freely (as long as we
+   are careful not to change the type of the overall expression).
+   We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR,
+   but we can constant-fold them if they have constant operands.  */
+
+#ifdef ENABLE_FOLD_CHECKING
+# define fold(x) fold_1 (x)
+static tree fold_1 (tree);
+static
+#endif
+tree
+fold (tree expr)
+{
+  const tree t = expr;
+  enum tree_code code = TREE_CODE (t);
+  enum tree_code_class kind = TREE_CODE_CLASS (code);
+  tree tem;
+
+  /* Return right away if a constant.  */
+  if (kind == tcc_constant)
+    return t;
+
+  if (IS_EXPR_CODE_CLASS (kind))
+    {
+      tree type = TREE_TYPE (t);
+      tree op0, op1, op2;
+
+      switch (TREE_CODE_LENGTH (code))
+       {
+       case 1:
+         op0 = TREE_OPERAND (t, 0);
+         tem = fold_unary (code, type, op0);
+         return tem ? tem : expr;
+       case 2:
+         op0 = TREE_OPERAND (t, 0);
+         op1 = TREE_OPERAND (t, 1);
+         tem = fold_binary (code, type, op0, op1);
+         return tem ? tem : expr;
+       case 3:
+         op0 = TREE_OPERAND (t, 0);
+         op1 = TREE_OPERAND (t, 1);
+         op2 = TREE_OPERAND (t, 2);
+         tem = fold_ternary (code, type, op0, op1, op2);
+         return tem ? tem : expr;
+       default:
+         break;
+       }
+    }
+
+  switch (code)
+    {
+    case CONST_DECL:
+      return fold (DECL_INITIAL (t));
 
     default:
       return t;
@@ -9994,8 +10107,11 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
       expr = (tree) buf;
       TYPE_POINTER_TO (expr) = NULL;
       TYPE_REFERENCE_TO (expr) = NULL;
-      TYPE_CACHED_VALUES_P (expr) = 0;
-      TYPE_CACHED_VALUES (expr) = NULL;
+      if (TYPE_CACHED_VALUES_P (expr))
+       {
+         TYPE_CACHED_VALUES_P (expr) = 0;
+         TYPE_CACHED_VALUES (expr) = NULL;
+       }
     }
   md5_process_bytes (expr, tree_size (expr), ctx);
   fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
@@ -10087,6 +10203,51 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
 
 #endif
 
+/* Fold a unary tree expression with code CODE of type TYPE with an
+   operand OP0.  Return a folded expression if successful.  Otherwise,
+   return a tree expression with code CODE of type TYPE with an
+   operand OP0.  */
+
+tree
+fold_build1 (enum tree_code code, tree type, tree op0)
+{
+  tree tem = fold_unary (code, type, op0);
+  if (tem)
+    return tem;
+
+  return build1 (code, type, op0);
+}
+
+/* Fold a binary tree expression with code CODE of type TYPE with
+   operands OP0 and OP1.  Return a folded expression if successful.
+   Otherwise, return a tree expression with code CODE of type TYPE
+   with operands OP0 and OP1.  */
+
+tree
+fold_build2 (enum tree_code code, tree type, tree op0, tree op1)
+{
+  tree tem = fold_binary (code, type, op0, op1);
+  if (tem)
+    return tem;
+
+  return build2 (code, type, op0, op1);
+}
+
+/* Fold a ternary tree expression with code CODE of type TYPE with
+   operands OP0, OP1, and OP2.  Return a folded expression if
+   successful.  Otherwise, return a tree expression with code CODE of
+   type TYPE with operands OP0, OP1, and OP2.  */
+
+tree
+fold_build3 (enum tree_code code, tree type, tree op0, tree op1, tree op2)
+{
+  tree tem = fold_ternary (code, type, op0, op1, op2);
+  if (tem)
+    return tem;
+
+  return build3 (code, type, op0, op1, op2);
+}
+
 /* Perform constant folding and related simplification of initializer
    expression EXPR.  This behaves identically to "fold" but ignores
    potential run-time traps and exceptions that fold must preserve.  */
@@ -11092,6 +11253,7 @@ fold_unary_to_constant (enum tree_code code, tree type, tree op0)
     case FIX_TRUNC_EXPR:
     case FIX_FLOOR_EXPR:
     case FIX_CEIL_EXPR:
+    case FIX_ROUND_EXPR:
       return fold_convert_const (code, type, op0);
 
     case NEGATE_EXPR:
@@ -11737,7 +11899,7 @@ ptr_difference_const (tree e1, tree e2, HOST_WIDE_INT *diff)
       if (type != TREE_TYPE (toffset2))
        toffset2 = fold_convert (type, toffset2);
 
-      tdiff = fold (build2 (MINUS_EXPR, type, toffset1, toffset2));
+      tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2);
       if (!host_integerp (tdiff, 0))
        return false;
 
@@ -11779,9 +11941,9 @@ fold_strip_sign_ops (tree exp)
       arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 0));
       arg1 = fold_strip_sign_ops (TREE_OPERAND (exp, 1));
       if (arg0 != NULL_TREE || arg1 != NULL_TREE)
-       return fold (build2 (TREE_CODE (exp), TREE_TYPE (exp),
-                            arg0 ? arg0 : TREE_OPERAND (exp, 0),
-                            arg1 ? arg1 : TREE_OPERAND (exp, 1)));
+       return fold_build2 (TREE_CODE (exp), TREE_TYPE (exp),
+                           arg0 ? arg0 : TREE_OPERAND (exp, 0),
+                           arg1 ? arg1 : TREE_OPERAND (exp, 1));
       break;
 
     default: