Index: fold-const.c
===================================================================
--- fold-const.c	(revision 210911)
+++ fold-const.c	(working copy)
@@ -8920,28 +8920,25 @@ fold_comparison (location_t loc, enum tr
   if (tree_swap_operands_p (arg0, arg1, true))
     return fold_build2_loc (loc, swap_tree_comparison (code), type, op1, op0);
 
-  /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 +- C1.  */
+  /* Transform comparisons of the form X +- C1 CMP C2 to X CMP C2 -+ C1.  */
   if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
-      && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-	  && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
-	  && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
-      && (TREE_CODE (arg1) == INTEGER_CST
-	  && !TREE_OVERFLOW (arg1)))
+      && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))
+      && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+      && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
+      && TREE_CODE (arg1) == INTEGER_CST
+      && !TREE_OVERFLOW (arg1))
     {
+      const enum tree_code
+	reverse_op = TREE_CODE (arg0) == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR;
       tree const1 = TREE_OPERAND (arg0, 1);
       tree const2 = arg1;
       tree variable = TREE_OPERAND (arg0, 0);
-      tree lhs;
-      int lhs_add;
-      lhs_add = TREE_CODE (arg0) != PLUS_EXPR;
-
-      lhs = fold_build2_loc (loc, lhs_add ? PLUS_EXPR : MINUS_EXPR,
-			 TREE_TYPE (arg1), const2, const1);
+      tree new_const
+	= fold_build2_loc (loc, reverse_op, TREE_TYPE (arg1), const2, const1);
 
       /* If the constant operation overflowed this can be
 	 simplified as a comparison against INT_MAX/INT_MIN.  */
-      if (TREE_CODE (lhs) == INTEGER_CST
-	  && TREE_OVERFLOW (lhs))
+      if (TREE_OVERFLOW (new_const))
 	{
 	  int const1_sgn = tree_int_cst_sgn (const1);
 	  enum tree_code code2 = code;
@@ -8961,29 +8958,48 @@ fold_comparison (location_t loc, enum tr
 	  /* We now can look at the canonicalized case
 	       VARIABLE + 1  CODE2  INT_MIN
 	     and decide on the result.  */
-	  if (code2 == LT_EXPR
-	      || code2 == LE_EXPR
-	      || code2 == EQ_EXPR)
-	    return omit_one_operand_loc (loc, type, boolean_false_node, variable);
-	  else if (code2 == NE_EXPR
-		   || code2 == GE_EXPR
-		   || code2 == GT_EXPR)
-	    return omit_one_operand_loc (loc, type, boolean_true_node, variable);
+	  switch (code2)
+	    {
+	    case EQ_EXPR:
+	    case LT_EXPR:
+	    case LE_EXPR:
+	      return
+		omit_one_operand_loc (loc, type, boolean_false_node, variable);
+
+	    case NE_EXPR:
+	    case GE_EXPR:
+	    case GT_EXPR:
+	      return
+		omit_one_operand_loc (loc, type, boolean_true_node, variable);
+
+	    default:
+	      gcc_unreachable ();
+	    }
 	}
-
-      if (TREE_CODE (lhs) == TREE_CODE (arg1)
-	  && (TREE_CODE (lhs) != INTEGER_CST
-	      || !TREE_OVERFLOW (lhs)))
+      else
 	{
 	  if (code != EQ_EXPR && code != NE_EXPR)
 	    fold_overflow_warning ("assuming signed overflow does not occur "
 				   "when changing X +- C1 cmp C2 to "
-				   "X cmp C1 +- C2",
+				   "X cmp C2 -+ C1",
 				   WARN_STRICT_OVERFLOW_COMPARISON);
-	  return fold_build2_loc (loc, code, type, variable, lhs);
+	  return fold_build2_loc (loc, code, type, variable, new_const);
 	}
     }
 
+  /* Transform comparisons of the form X - Y CMP 0 to X CMP Y.  */
+  if (TREE_CODE (arg0) == MINUS_EXPR
+      && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))
+      && integer_zerop (arg1))
+    {
+      if (code != EQ_EXPR && code != NE_EXPR)
+	fold_overflow_warning ("assuming signed overflow does not occur "
+			       "when changing X - Y cmp 0 to X cmp Y",
+			       WARN_STRICT_OVERFLOW_COMPARISON);
+      return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0),
+			      TREE_OPERAND (arg0, 1));
+    }
+
   /* For comparisons of pointers we can decompose it to a compile time
      comparison of the base objects and the offsets into the object.
      This requires at least one operand being an ADDR_EXPR or a
Index: tree-vrp.c
===================================================================
--- tree-vrp.c	(revision 210911)
+++ tree-vrp.c	(working copy)
@@ -6966,6 +6966,46 @@ vrp_evaluate_conditional_warnv_with_ops
   return NULL_TREE;
 }
 
+/* Helper function for vrp_evaluate_conditional_warnv.  */
+
+static tree
+vrp_evaluate_conditional_warnv_with_fold (gimple stmt, enum tree_code code,
+					  tree op0, tree op1,
+					  bool use_equiv_p,
+					  bool *strict_overflow_p,
+					  bool *only_ranges)
+{
+  const location_t loc = gimple_location (stmt);
+
+  fold_defer_overflow_warnings ();
+
+  tree t = fold_binary_loc (loc, code, boolean_type_node, op0, op1);
+  if (!t
+      || !COMPARISON_CLASS_P (t)
+      || !is_gimple_val (TREE_OPERAND (t, 0))
+      || !is_gimple_val (TREE_OPERAND (t, 1)))
+    {
+      fold_undefer_overflow_warnings (false, NULL, 0);
+      return NULL_TREE;
+    }
+
+  tree ret = vrp_evaluate_conditional_warnv_with_ops (TREE_CODE (t),
+						      TREE_OPERAND (t, 0),
+						      TREE_OPERAND (t, 1),
+						      use_equiv_p,
+						      strict_overflow_p,
+						      only_ranges);
+  if (!ret)
+    {
+      fold_undefer_overflow_warnings (false, NULL, 0);
+      return NULL_TREE;
+    }
+
+  fold_undefer_overflow_warnings (!gimple_no_warning_p (stmt), stmt, 0);
+
+  return ret;
+}
+
 /* Given (CODE OP0 OP1) within STMT, try to simplify it based on value range
    information.  Return NULL if the conditional can not be evaluated.
    The ranges of all the names equivalent with the operands in COND
@@ -6992,6 +7032,47 @@ vrp_evaluate_conditional (enum tree_code
   ret = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, true, &sop,
   						 &only_ranges);
 
+  /* The propagation machinery doesn't handle symbolic ranges in conjunction
+     with PLUS_EXPR or MINUS_EXPR so we try to jump over them by propagating
+     their operands instead.  */
+  if (!ret
+      && TREE_CODE (op0) == SSA_NAME
+      && is_gimple_assign (SSA_NAME_DEF_STMT (op0)))
+    {
+      gimple def_stmt = SSA_NAME_DEF_STMT (op0);
+      enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
+      if (def_code == PLUS_EXPR || def_code == MINUS_EXPR)
+	{
+	  tree new_op0 = fold_build2_loc (gimple_location (def_stmt),
+					  def_code, TREE_TYPE (op0),
+					  gimple_assign_rhs1 (def_stmt),
+					  gimple_assign_rhs2 (def_stmt));
+	  ret = vrp_evaluate_conditional_warnv_with_fold (stmt, code,
+							  new_op0, op1,
+							  true, &sop,
+							  &only_ranges);
+	}
+    }
+
+  if (!ret
+      && TREE_CODE (op1) == SSA_NAME
+      && is_gimple_assign (SSA_NAME_DEF_STMT (op1)))
+    {
+      gimple def_stmt = SSA_NAME_DEF_STMT (op1);
+      enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
+      if (def_code == PLUS_EXPR || def_code == MINUS_EXPR)
+	{
+	  tree new_op1 = fold_build2_loc (gimple_location (def_stmt),
+					  def_code, TREE_TYPE (op1),
+					  gimple_assign_rhs1 (def_stmt),
+					  gimple_assign_rhs2 (def_stmt));
+	  ret = vrp_evaluate_conditional_warnv_with_fold (stmt, code,
+							  op0, new_op1,
+							  true, &sop,
+							  &only_ranges);
+	}
+    }
+
   if (ret && sop)
     {
       enum warn_strict_overflow_code wc;