OSDN Git Service

* gcc.dg/altivec-vec-merge.c: Make test usable on GNU/Linux targets
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 203fbc5..050d45c 100644 (file)
@@ -831,6 +831,33 @@ div_and_round_double (enum tree_code code, int uns,
   add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
   return overflow;
 }
+
+/* If ARG2 divides ARG1 with zero remainder, carries out the division
+   of type CODE and returns the quotient.
+   Otherwise returns NULL_TREE.  */
+
+static tree
+div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2)
+{
+  unsigned HOST_WIDE_INT int1l, int2l;
+  HOST_WIDE_INT int1h, int2h;
+  unsigned HOST_WIDE_INT quol, reml;
+  HOST_WIDE_INT quoh, remh;
+  tree type = TREE_TYPE (arg1);
+  int uns = TYPE_UNSIGNED (type);
+
+  int1l = TREE_INT_CST_LOW (arg1);
+  int1h = TREE_INT_CST_HIGH (arg1);
+  int2l = TREE_INT_CST_LOW (arg2);
+  int2h = TREE_INT_CST_HIGH (arg2);
+
+  div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
+                       &quol, &quoh, &reml, &remh);
+  if (remh != 0 || reml != 0)
+    return NULL_TREE;
+
+  return build_int_cst_wide (type, quol, quoh);
+}
 \f
 /* Return true if built-in mathematical function specified by CODE
    preserves the sign of it argument, i.e. -f(x) == f(-x).  */
@@ -3076,6 +3103,46 @@ distribute_bit_expr (enum tree_code code, tree type, tree arg0, tree arg1)
   return fold_build2 (TREE_CODE (arg0), type, common,
                      fold_build2 (code, type, left, right));
 }
+
+/* Knowing that ARG0 and ARG1 are both RDIV_EXPRs, simplify a binary operation
+   with code CODE.  This optimization is unsafe.  */
+static tree
+distribute_real_division (enum tree_code code, tree type, tree arg0, tree arg1)
+{
+  bool mul0 = TREE_CODE (arg0) == MULT_EXPR;
+  bool mul1 = TREE_CODE (arg1) == MULT_EXPR;
+
+  /* (A / C) +- (B / C) -> (A +- B) / C.  */
+  if (mul0 == mul1
+      && operand_equal_p (TREE_OPERAND (arg0, 1),
+                      TREE_OPERAND (arg1, 1), 0))
+    return fold_build2 (mul0 ? MULT_EXPR : RDIV_EXPR, type,
+                       fold_build2 (code, type,
+                                    TREE_OPERAND (arg0, 0),
+                                    TREE_OPERAND (arg1, 0)),
+                       TREE_OPERAND (arg0, 1));
+
+  /* (A / C1) +- (A / C2) -> A * (1 / C1 +- 1 / C2).  */
+  if (operand_equal_p (TREE_OPERAND (arg0, 0),
+                      TREE_OPERAND (arg1, 0), 0)
+      && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+      && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
+    {
+      REAL_VALUE_TYPE r0, r1;
+      r0 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+      r1 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+      if (!mul0)
+       real_arithmetic (&r0, RDIV_EXPR, &dconst1, &r0);
+      if (!mul1)
+        real_arithmetic (&r1, RDIV_EXPR, &dconst1, &r1);
+      real_arithmetic (&r0, code, &r0, &r1);
+      return fold_build2 (MULT_EXPR, type,
+                         TREE_OPERAND (arg0, 0),
+                         build_real (type, r0));
+    }
+
+  return NULL_TREE;
+}
 \f
 /* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
    starting at BITPOS.  The field is unsigned if UNSIGNEDP is nonzero.  */
@@ -3226,7 +3293,7 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
                                        fold_convert (unsigned_type, rhs),
                                        size_int (lbitsize), 0)))
        {
-         warning ("comparison is always %d due to width of bit-field",
+         warning (0, "comparison is always %d due to width of bit-field",
                   code == NE_EXPR);
          return constant_boolean_node (code == NE_EXPR, compare_type);
        }
@@ -3237,7 +3304,7 @@ optimize_bit_field_compare (enum tree_code code, tree compare_type,
                              size_int (lbitsize - 1), 0);
       if (! integer_zerop (tem) && ! integer_all_onesp (tem))
        {
-         warning ("comparison is always %d due to width of bit-field",
+         warning (0, "comparison is always %d due to width of bit-field",
                   code == NE_EXPR);
          return constant_boolean_node (code == NE_EXPR, compare_type);
        }
@@ -4808,7 +4875,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
                                                     lntype, ll_mask),
                                        0)))
        {
-         warning ("comparison is always %d", wanted_code == NE_EXPR);
+         warning (0, "comparison is always %d", wanted_code == NE_EXPR);
 
          return constant_boolean_node (wanted_code == NE_EXPR, truth_type);
        }
@@ -4823,7 +4890,7 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
                                                     lntype, rl_mask),
                                        0)))
        {
-         warning ("comparison is always %d", wanted_code == NE_EXPR);
+         warning (0, "comparison is always %d", wanted_code == NE_EXPR);
 
          return constant_boolean_node (wanted_code == NE_EXPR, truth_type);
        }
@@ -4952,12 +5019,12 @@ fold_truthop (enum tree_code code, tree truth_type, tree lhs, tree rhs)
     {
       if (wanted_code == NE_EXPR)
        {
-         warning ("%<or%> of unmatched not-equal tests is always 1");
+         warning (0, "%<or%> of unmatched not-equal tests is always 1");
          return constant_boolean_node (true, truth_type);
        }
       else
        {
-         warning ("%<and%> of mutually exclusive equal-tests is always 0");
+         warning (0, "%<and%> of mutually exclusive equal-tests is always 0");
          return constant_boolean_node (false, truth_type);
        }
     }
@@ -5929,30 +5996,23 @@ fold_div_compare (enum tree_code code, tree type, tree arg0, tree arg1)
 
 
 /* If CODE with arguments ARG0 and ARG1 represents a single bit
-   equality/inequality test, then return a simplified form of
-   the test using shifts and logical operations.  Otherwise return
-   NULL.  TYPE is the desired result type.  */
+   equality/inequality test, then return a simplified form of the test
+   using a sign testing.  Otherwise return NULL.  TYPE is the desired
+   result type.  */
 
-tree
-fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
-                     tree result_type)
+static tree
+fold_single_bit_test_into_sign_test (enum tree_code code, tree arg0, tree arg1,
+                                    tree result_type)
 {
   /* If this is testing a single bit, we can optimize the test.  */
   if ((code == NE_EXPR || code == EQ_EXPR)
       && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
       && integer_pow2p (TREE_OPERAND (arg0, 1)))
     {
-      tree inner = TREE_OPERAND (arg0, 0);
-      tree type = TREE_TYPE (arg0);
-      int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
-      enum machine_mode operand_mode = TYPE_MODE (type);
-      int ops_unsigned;
-      tree signed_type, unsigned_type, intermediate_type;
-      tree arg00;
-
       /* If we have (A & C) != 0 where C is the sign bit of A, convert
         this into A < 0.  Similarly for (A & C) == 0 into A >= 0.  */
-      arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
+      tree arg00 = sign_bit_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1));
+
       if (arg00 != NULL_TREE
          /* This is only a win if casting to a signed type is cheap,
             i.e. when arg00's type is not a partial mode.  */
@@ -5964,6 +6024,39 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
                              result_type, fold_convert (stype, arg00),
                              fold_convert (stype, integer_zero_node));
        }
+    }
+
+  return NULL_TREE;
+}
+
+/* If CODE with arguments ARG0 and ARG1 represents a single bit
+   equality/inequality test, then return a simplified form of
+   the test using shifts and logical operations.  Otherwise return
+   NULL.  TYPE is the desired result type.  */
+
+tree
+fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
+                     tree result_type)
+{
+  /* If this is testing a single bit, we can optimize the test.  */
+  if ((code == NE_EXPR || code == EQ_EXPR)
+      && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
+      && integer_pow2p (TREE_OPERAND (arg0, 1)))
+    {
+      tree inner = TREE_OPERAND (arg0, 0);
+      tree type = TREE_TYPE (arg0);
+      int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
+      enum machine_mode operand_mode = TYPE_MODE (type);
+      int ops_unsigned;
+      tree signed_type, unsigned_type, intermediate_type;
+      tree tem;
+
+      /* First, see if we can fold the single bit test into a sign-bit
+        test.  */
+      tem = fold_single_bit_test_into_sign_test (code, arg0, arg1,
+                                                result_type);
+      if (tem)
+       return tem;
 
       /* Otherwise we have (A & C) != 0 where C is a single bit,
         convert that into ((A >> C2) & 1).  Where C2 = log2(C).
@@ -6123,7 +6216,8 @@ fold_widened_comparison (enum tree_code code, tree type, tree arg0, tree arg1)
        || TYPE_UNSIGNED (TREE_TYPE (arg0)) == TYPE_UNSIGNED (shorter_type))
       && (TREE_TYPE (arg1_unw) == shorter_type
          || (TREE_CODE (arg1_unw) == INTEGER_CST
-             && TREE_CODE (shorter_type) == INTEGER_TYPE
+             && (TREE_CODE (shorter_type) == INTEGER_TYPE
+                 || TREE_CODE (shorter_type) == BOOLEAN_TYPE)
              && int_fits_type_p (arg1_unw, shorter_type))))
     return fold_build2 (code, type, arg0_unw,
                       fold_convert (shorter_type, arg1_unw));
@@ -6232,55 +6326,80 @@ fold_sign_changed_comparison (enum tree_code code, tree type,
 }
 
 /* Tries to replace &a[idx] CODE s * delta with &a[idx CODE delta], if s is
-   step of the array.  ADDR is the address. MULT is the multiplicative expression.
+   step of the array.  Reconstructs s and delta in the case of s * delta
+   being an integer constant (and thus already folded).
+   ADDR is the address. MULT is the multiplicative expression.
    If the function succeeds, the new address expression is returned.  Otherwise
    NULL_TREE is returned.  */
 
 static tree
-try_move_mult_to_index (enum tree_code code, tree addr, tree mult)
+try_move_mult_to_index (enum tree_code code, tree addr, tree op1)
 {
   tree s, delta, step;
-  tree arg0 = TREE_OPERAND (mult, 0), arg1 = TREE_OPERAND (mult, 1);
   tree ref = TREE_OPERAND (addr, 0), pref;
   tree ret, pos;
   tree itype;
 
-  STRIP_NOPS (arg0);
-  STRIP_NOPS (arg1);
-  
-  if (TREE_CODE (arg0) == INTEGER_CST)
+  /* Canonicalize op1 into a possibly non-constant delta
+     and an INTEGER_CST s.  */
+  if (TREE_CODE (op1) == MULT_EXPR)
     {
-      s = arg0;
-      delta = arg1;
+      tree arg0 = TREE_OPERAND (op1, 0), arg1 = TREE_OPERAND (op1, 1);
+
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+  
+      if (TREE_CODE (arg0) == INTEGER_CST)
+        {
+          s = arg0;
+          delta = arg1;
+        }
+      else if (TREE_CODE (arg1) == INTEGER_CST)
+        {
+          s = arg1;
+          delta = arg0;
+        }
+      else
+        return NULL_TREE;
     }
-  else if (TREE_CODE (arg1) == INTEGER_CST)
+  else if (TREE_CODE (op1) == INTEGER_CST)
     {
-      s = arg1;
-      delta = arg0;
+      delta = op1;
+      s = NULL_TREE;
     }
   else
-    return NULL_TREE;
+    {
+      /* Simulate we are delta * 1.  */
+      delta = op1;
+      s = integer_one_node;
+    }
 
   for (;; ref = TREE_OPERAND (ref, 0))
     {
       if (TREE_CODE (ref) == ARRAY_REF)
        {
-         step = array_ref_element_size (ref);
-
-         if (TREE_CODE (step) != INTEGER_CST)
+         itype = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (ref, 0)));
+         if (! itype)
            continue;
 
-         itype = TREE_TYPE (step);
-
-         /* If the type sizes do not match, we might run into problems
-            when one of them would overflow.  */
-         if (TYPE_PRECISION (itype) != TYPE_PRECISION (TREE_TYPE (s)))
+         step = array_ref_element_size (ref);
+         if (TREE_CODE (step) != INTEGER_CST)
            continue;
 
-         if (!operand_equal_p (step, fold_convert (itype, s), 0))
-           continue;
+         if (s)
+           {
+             if (! tree_int_cst_equal (step, s))
+                continue;
+           }
+         else
+           {
+             /* Try if delta is a multiple of step.  */
+             tree tmp = div_if_zero_remainder (EXACT_DIV_EXPR, delta, step);
+             if (! tmp)
+               continue;
+             delta = tmp;
+           }
 
-         delta = fold_convert (itype, delta);
          break;
        }
 
@@ -6303,8 +6422,9 @@ try_move_mult_to_index (enum tree_code code, tree addr, tree mult)
     }
 
   TREE_OPERAND (pos, 1) = fold_build2 (code, itype,
-                                      TREE_OPERAND (pos, 1),
-                                      delta);
+                                      fold_convert (itype,
+                                                    TREE_OPERAND (pos, 1)),
+                                      fold_convert (itype, delta));
 
   return build1 (ADDR_EXPR, TREE_TYPE (addr), ret);
 }
@@ -6652,7 +6772,7 @@ fold_complex_div (tree type, tree ac, tree bc, enum tree_code code)
    OP0.  Return the folded expression if folding is successful.
    Otherwise, return NULL_TREE.  */
 
-static tree
+tree
 fold_unary (enum tree_code code, tree type, tree op0)
 {
   tree tem;
@@ -7015,6 +7135,20 @@ fold_unary (enum tree_code code, tree type, tree op0)
                   || (TREE_CODE (arg0) == PLUS_EXPR
                       && integer_all_onesp (TREE_OPERAND (arg0, 1)))))
        return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
+      /* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify.  */
+      else if (TREE_CODE (arg0) == BIT_XOR_EXPR
+              && (tem = fold_unary (BIT_NOT_EXPR, type,
+                                    fold_convert (type,
+                                                  TREE_OPERAND (arg0, 0)))))
+       return fold_build2 (BIT_XOR_EXPR, type, tem,
+                           fold_convert (type, TREE_OPERAND (arg0, 1)));
+      else if (TREE_CODE (arg0) == BIT_XOR_EXPR
+              && (tem = fold_unary (BIT_NOT_EXPR, type,
+                                    fold_convert (type,
+                                                  TREE_OPERAND (arg0, 1)))))
+       return fold_build2 (BIT_XOR_EXPR, type,
+                           fold_convert (type, TREE_OPERAND (arg0, 0)), tem);
+
       return NULL_TREE;
 
     case TRUTH_NOT_EXPR:
@@ -7073,7 +7207,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
    OP0 and OP1.  Return the folded expression if folding is
    successful.  Otherwise, return NULL_TREE.  */
 
-static tree
+tree
 fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 {
   tree t1 = NULL_TREE;
@@ -7250,11 +7384,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
     case PLUS_EXPR:
       /* A + (-B) -> A - B */
       if (TREE_CODE (arg1) == NEGATE_EXPR)
-       return fold_build2 (MINUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0));
+       return fold_build2 (MINUS_EXPR, type,
+                           fold_convert (type, arg0),
+                           fold_convert (type, 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));
+       return fold_build2 (MINUS_EXPR, type,
+                           fold_convert (type, arg1),
+                           fold_convert (type, TREE_OPERAND (arg0, 0)));
       /* Convert ~A + 1 to -A.  */
       if (INTEGRAL_TYPE_P (type)
          && TREE_CODE (arg0) == BIT_NOT_EXPR
@@ -7390,21 +7528,19 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                    fold_build2 (PLUS_EXPR, type,
                                                 fold_convert (type, alt0),
                                                 fold_convert (type, alt1)),
-                                   same);
+                                   fold_convert (type, same));
            }
 
          /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
             of the array.  Loop optimizer sometimes produce this type of
             expressions.  */
-         if (TREE_CODE (arg0) == ADDR_EXPR
-             && TREE_CODE (arg1) == MULT_EXPR)
+         if (TREE_CODE (arg0) == ADDR_EXPR)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg0, arg1);
              if (tem)
                return fold_convert (type, fold (tem));
            }
-         else if (TREE_CODE (arg1) == ADDR_EXPR
-                  && TREE_CODE (arg0) == MULT_EXPR)
+         else if (TREE_CODE (arg1) == ADDR_EXPR)
            {
              tem = try_move_mult_to_index (PLUS_EXPR, arg1, arg0);
              if (tem)
@@ -7432,6 +7568,12 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                    fold_convert (type, tem));
            }
 
+          if (flag_unsafe_math_optimizations
+             && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
+             && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
+             && (tem = distribute_real_division (code, type, arg0, arg1)))
+           return tem;
+
          /* Convert x+x into x*2.0.  */
          if (operand_equal_p (arg0, arg1, 0)
              && SCALAR_FLOAT_TYPE_P (type))
@@ -7797,18 +7939,44 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            && ptr_difference_const (arg0, arg1, &diff))
          return build_int_cst_type (type, diff);
       }
-         
+
+      /* Fold &a[i] - &a[j] to i-j.  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF
+         && TREE_CODE (arg1) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF)
+        {
+         tree aref0 = TREE_OPERAND (arg0, 0);
+         tree aref1 = TREE_OPERAND (arg1, 0);
+         if (operand_equal_p (TREE_OPERAND (aref0, 0),
+                              TREE_OPERAND (aref1, 0), 0))
+           {
+             tree op0 = fold_convert (type, TREE_OPERAND (aref0, 1));
+             tree op1 = fold_convert (type, TREE_OPERAND (aref1, 1));
+             tree esz = array_ref_element_size (aref0);
+             tree diff = build2 (MINUS_EXPR, type, op0, op1);
+             return fold_build2 (MULT_EXPR, type, diff,
+                                 fold_convert (type, esz));
+                                 
+           }
+       }
+
       /* Try replacing &a[i1] - c * i2 with &a[i1 - i2], if c is step
         of the array.  Loop optimizer sometimes produce this type of
         expressions.  */
-      if (TREE_CODE (arg0) == ADDR_EXPR
-         && TREE_CODE (arg1) == MULT_EXPR)
+      if (TREE_CODE (arg0) == ADDR_EXPR)
        {
          tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1);
          if (tem)
            return fold_convert (type, fold (tem));
        }
 
+      if (flag_unsafe_math_optimizations
+         && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
+         && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
+         && (tem = distribute_real_division (code, type, arg0, arg1)))
+       return tem;
+
       if (TREE_CODE (arg0) == MULT_EXPR
          && TREE_CODE (arg1) == MULT_EXPR
          && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
@@ -8170,6 +8338,13 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          goto bit_ior;
        }
 
+      /* Convert ~X ^ ~Y to X ^ Y.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+         && TREE_CODE (arg1) == BIT_NOT_EXPR)
+       return fold_build2 (code, type,
+                           fold_convert (type, TREE_OPERAND (arg0, 0)),
+                           fold_convert (type, TREE_OPERAND (arg1, 0)));
+
       /* See if this can be simplified into a rotate first.  If that
         is unsuccessful continue in the association code.  */
       goto bit_rotate;
@@ -8500,6 +8675,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       if (code == TRUNC_MOD_EXPR
          && !TYPE_UNSIGNED (type)
          && TREE_CODE (arg1) == INTEGER_CST
+         && !TREE_CONSTANT_OVERFLOW (arg1)
          && TREE_INT_CST_HIGH (arg1) < 0
          && !flag_trapv
          /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
@@ -8783,10 +8959,20 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
     case LT_EXPR:
     case GT_EXPR:
     case LE_EXPR:
-    case GE_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, op1, op0);
+       
+      /* bool_var != 0 becomes bool_var. */
+      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
+          && code == NE_EXPR)
+        return non_lvalue (fold_convert (type, arg0));
+       
+      /* bool_var == 1 becomes bool_var. */
+      if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
+          && code == EQ_EXPR)
+        return non_lvalue (fold_convert (type, arg0));
 
       /* If this is an equality comparison of the address of a non-weak
         object against zero, then we know the result.  */
@@ -8844,6 +9030,77 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            }
        }
 
+      /* Transform comparisons of the form X +- C CMP X.  */
+      if ((code != EQ_EXPR && code != NE_EXPR)
+         && (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+         && ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+              && !HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
+             || (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+                 && !TYPE_UNSIGNED (TREE_TYPE (arg1))
+                 && !(flag_wrapv || flag_trapv))))
+       {
+         tree arg01 = TREE_OPERAND (arg0, 1);
+         enum tree_code code0 = TREE_CODE (arg0);
+         int is_positive;
+
+         if (TREE_CODE (arg01) == REAL_CST)
+           is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1;
+         else
+           is_positive = tree_int_cst_sgn (arg01);
+
+         /* (X - c) > X becomes false.  */
+         if (code == GT_EXPR
+             && ((code0 == MINUS_EXPR && is_positive >= 0)
+                 || (code0 == PLUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (0, type);
+
+         /* Likewise (X + c) < X becomes false.  */
+         if (code == LT_EXPR
+             && ((code0 == PLUS_EXPR && is_positive >= 0)
+                 || (code0 == MINUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (0, type);
+
+         /* Convert (X - c) <= X to true.  */
+         if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
+             && code == LE_EXPR
+             && ((code0 == MINUS_EXPR && is_positive >= 0)
+                 || (code0 == PLUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (1, type);
+
+         /* Convert (X + c) >= X to true.  */
+         if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
+             && code == GE_EXPR
+             && ((code0 == PLUS_EXPR && is_positive >= 0)
+                 || (code0 == MINUS_EXPR && is_positive <= 0)))
+           return constant_boolean_node (1, type);
+
+         if (TREE_CODE (arg01) == INTEGER_CST)
+           {
+             /* Convert X + c > X and X - c < X to true for integers.  */
+             if (code == GT_EXPR
+                 && ((code0 == PLUS_EXPR && is_positive > 0)
+                     || (code0 == MINUS_EXPR && is_positive < 0)))
+               return constant_boolean_node (1, type);
+
+             if (code == LT_EXPR
+                 && ((code0 == MINUS_EXPR && is_positive > 0)
+                     || (code0 == PLUS_EXPR && is_positive < 0)))
+               return constant_boolean_node (1, type);
+
+             /* Convert X + c <= X and X - c >= X to false for integers.  */
+             if (code == LE_EXPR
+                 && ((code0 == PLUS_EXPR && is_positive > 0)
+                     || (code0 == MINUS_EXPR && is_positive < 0)))
+               return constant_boolean_node (0, type);
+
+             if (code == GE_EXPR
+                 && ((code0 == MINUS_EXPR && is_positive > 0)
+                     || (code0 == PLUS_EXPR && is_positive < 0)))
+               return constant_boolean_node (0, type);
+           }
+       }
+
       if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
        {
          tree targ0 = strip_float_extensions (arg0);
@@ -9350,9 +9607,9 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                            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.  */
-      tem = fold_single_bit_test (code, arg0, arg1, type);
+      /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign
+        bit, then fold the expression into A < 0 or A >= 0.  */
+      tem = fold_single_bit_test_into_sign_test (code, arg0, arg1, type);
       if (tem)
        return tem;
 
@@ -9564,6 +9821,27 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            return t1;
        }
 
+      /* Fold a comparison of the address of COMPONENT_REFs with the same
+         type and component to a comparison of the address of the base
+        object.  In short, &x->a OP &y->a to x OP y and
+         &x->a OP &y.a to x OP &y  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == COMPONENT_REF
+         && TREE_CODE (arg1) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (arg1, 0)) == COMPONENT_REF)
+        {
+         tree cref0 = TREE_OPERAND (arg0, 0);
+         tree cref1 = TREE_OPERAND (arg1, 0);
+         if (TREE_OPERAND (cref0, 1) == TREE_OPERAND (cref1, 1))
+           {
+             tree op0 = TREE_OPERAND (cref0, 0);
+             tree op1 = TREE_OPERAND (cref1, 0);
+             return fold_build2 (code, type,
+                                 build_fold_addr_expr (op0),
+                                 build_fold_addr_expr (op1));
+           }
+       }
+
       /* If this is a comparison of complex values and either or both sides
         are a COMPLEX_EXPR or COMPLEX_CST, it is best to split up the
         comparisons and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR.
@@ -9720,16 +9998,51 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
        return build_complex (type, arg0, arg1);
       return NULL_TREE;
 
+    case ASSERT_EXPR:
+      /* An ASSERT_EXPR should never be passed to fold_binary.  */
+      gcc_unreachable ();
+
     default:
       return NULL_TREE;
     } /* switch (code) */
 }
 
+/* Callback for walk_tree, looking for LABEL_EXPR.
+   Returns tree TP if it is LABEL_EXPR. Otherwise it returns NULL_TREE.
+   Do not check the sub-tree of GOTO_EXPR.  */
+
+static tree
+contains_label_1 (tree *tp,
+                  int *walk_subtrees,
+                  void *data ATTRIBUTE_UNUSED)
+{
+  switch (TREE_CODE (*tp))
+    {
+    case LABEL_EXPR:
+      return *tp;
+    case GOTO_EXPR:
+      *walk_subtrees = 0;
+    /* no break */
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Checks whether the sub-tree ST contains a label LABEL_EXPR which is
+   accessible from outside the sub-tree. Returns NULL_TREE if no
+   addressable label is found.  */
+
+static bool
+contains_label_p (tree st)
+{
+  return (walk_tree (&st, contains_label_1 , NULL, NULL) != NULL_TREE);
+}
+
 /* 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
+tree
 fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
 {
   tree tem;
@@ -9778,12 +10091,16 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
         so all simple results must be passed through pedantic_non_lvalue.  */
       if (TREE_CODE (arg0) == INTEGER_CST)
        {
+         tree unused_op = integer_zerop (arg0) ? op1 : op2;
          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))
+             away "c ? x : throw", where the throw has a void type.
+             Avoid throwing away that operand which contains label.  */
+          if ((!TREE_SIDE_EFFECTS (unused_op)
+               || !contains_label_p (unused_op))
+              && (! VOID_TYPE_P (TREE_TYPE (tem))
+                  || VOID_TYPE_P (type)))
            return pedantic_non_lvalue (tem);
          return NULL_TREE;
        }
@@ -10003,21 +10320,6 @@ fold (tree expr)
     case CONST_DECL:
       return fold (DECL_INITIAL (t));
 
-    case ASSERT_EXPR:
-      {
-       /* Given ASSERT_EXPR <Y, COND>, return Y if COND can be folded
-          to boolean_true_node.  If COND folds to boolean_false_node,
-          return ASSERT_EXPR <Y, 0>.  Otherwise, return the original
-          expression.  */
-       tree c = fold (ASSERT_EXPR_COND (t));
-       if (c == boolean_true_node)
-         return ASSERT_EXPR_VAR (t);
-       else if (c == boolean_false_node)
-         return build (ASSERT_EXPR, TREE_TYPE (t), ASSERT_EXPR_VAR (t), c);
-       else
-         return t;
-      }
-
     default:
       return t;
     } /* switch (code) */