diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index ff82591..4eeab98 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -96,6 +96,15 @@ static void vrp_intersect_ranges (value_range_t *, value_range_t *);
 static tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
 						     tree, tree, bool, bool *,
 						     bool *);
+static void extract_range_from_comparison (value_range_t *vr,
+					   enum tree_code code,
+					   tree type, tree op0, tree op1);
+static void simplify_ccmp_to_op (gimple_stmt_iterator *gsi, tree op);
+static void simplify_ccmp_to_cmp (gimple_stmt_iterator *, gimple,
+				  enum tree_code);
+static bool simple_ccmp_second_compare (gimple_stmt_iterator *gsi, gimple stmt);
+static bool can_simplify_ops_using_ranges_p (tree, tree, enum tree_code, tree);
+static bool simplify_ccmp_stmt_using_ranges (gimple_stmt_iterator *gsi);
 
 /* Location information for ASSERT_EXPRs.  Each instance of this
    structure describes an ASSERT_EXPR for an SSA name.  Since a single
@@ -3486,6 +3495,36 @@ extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
   extract_range_from_unary_expr_1 (vr, code, type, &vr0, TREE_TYPE (op0));
 }
 
+/* Extract range information from a conditional compare expression STMT based
+   on the ranges of each of its operands and the expression code.  */
+
+static void
+extract_range_from_ccomare_expr (value_range_t *vr, gimple stmt)
+{
+  tree op0, op1, type;
+  enum tree_code code, ncode, icode;
+  value_range_t vr0 = VR_INITIALIZER;
+  value_range_t vr1 = VR_INITIALIZER;
+
+  /* Get value ranges for each operand.  For constant operands, create
+     a new value range with the operand to simplify processing.  */
+  code = gimple_assign_rhs_code (stmt);
+  ncode = get_code_from_ccompare_expr (&icode, code);
+  type = gimple_expr_type (stmt);
+  op0 = gimple_assign_rhs1 (stmt);
+  op1 = gimple_assign_rhs2 (stmt);
+  extract_range_from_comparison (&vr0, ncode, type, op0, op1);
+
+  op1 = gimple_assign_rhs3 (stmt);
+  if (TREE_CODE (op1) == SSA_NAME)
+    vr1 = *(get_value_range (op1));
+  else if (is_gimple_min_invariant (op1))
+    set_value_range_to_value (&vr1, op1, NULL);
+  else
+    set_value_range_to_varying (&vr1);
+
+  extract_range_from_binary_expr_1 (vr, icode, type, &vr1, &vr0);
+}
 
 /* Extract range information from a conditional expression STMT based on
    the ranges of each of its operands and the expression code.  */
@@ -3781,6 +3820,8 @@ extract_range_from_assignment (value_range_t *vr, gimple stmt)
 				   gimple_expr_type (stmt),
 				   gimple_assign_rhs1 (stmt),
 				   gimple_assign_rhs2 (stmt));
+  else if (TREE_CODE_CLASS (code) == tcc_ccomparison)
+    extract_range_from_ccomare_expr (vr, stmt);
   else if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS
 	   && is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
     set_value_range_to_value (vr, gimple_assign_rhs1 (stmt), NULL);
@@ -5477,40 +5518,80 @@ register_edge_assert_for (tree name, edge e, gimple_stmt_iterator si,
      statement of NAME we can assert both operands of the BIT_AND_EXPR
      have nonzero value.  */
   if (((comp_code == EQ_EXPR && integer_onep (val))
-       || (comp_code == NE_EXPR && integer_zerop (val))))
+       || (comp_code == NE_EXPR && integer_zerop (val)))
+      && is_gimple_assign (SSA_NAME_DEF_STMT (name)))
     {
       gimple def_stmt = SSA_NAME_DEF_STMT (name);
-
-      if (is_gimple_assign (def_stmt)
-	  && gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR)
+      enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
+      enum tree_code ncode = def_code, icode = MAX_TREE_CODES;
+      if (TREE_CODE_CLASS (def_code) == tcc_ccomparison)
+	{
+	  ncode = get_code_from_ccompare_expr (&icode, def_code);
+	}
+      if (def_code == BIT_AND_EXPR)
 	{
 	  tree op0 = gimple_assign_rhs1 (def_stmt);
 	  tree op1 = gimple_assign_rhs2 (def_stmt);
 	  retval |= register_edge_assert_for_1 (op0, NE_EXPR, e, si);
 	  retval |= register_edge_assert_for_1 (op1, NE_EXPR, e, si);
 	}
+      else if (icode == BIT_AND_EXPR)
+	{
+	  tree op0 = gimple_assign_rhs1 (def_stmt);
+	  tree op1 = gimple_assign_rhs2 (def_stmt);
+	  tree op2 = gimple_assign_rhs3 (def_stmt);
+	  retval |= register_edge_assert_for_1 (op2, NE_EXPR, e, si);
+
+	  if (TREE_CODE (op0) == SSA_NAME)
+	    retval |= register_edge_assert_for_2 (op0, e, si, ncode, op0, op1,
+						  false);
+	  if (TREE_CODE (op1) == SSA_NAME)
+	    retval |= register_edge_assert_for_2 (op1, e, si, ncode, op0, op1,
+						  false);
+	}
     }
 
   /* In the case of NAME == 0 or NAME != 1, for BIT_IOR_EXPR defining
      statement of NAME we can assert both operands of the BIT_IOR_EXPR
      have zero value.  */
   if (((comp_code == EQ_EXPR && integer_zerop (val))
-       || (comp_code == NE_EXPR && integer_onep (val))))
+       || (comp_code == NE_EXPR && integer_onep (val)))
+      && (is_gimple_assign (SSA_NAME_DEF_STMT (name))))
     {
       gimple def_stmt = SSA_NAME_DEF_STMT (name);
+      enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
+      enum tree_code ncode = def_code, icode = MAX_TREE_CODES;
+      if (TREE_CODE_CLASS (def_code) == tcc_ccomparison)
+	{
+	  ncode = get_code_from_ccompare_expr (&icode, def_code);
+	}
 
       /* For BIT_IOR_EXPR only if NAME == 0 both operands have
 	 necessarily zero value, or if type-precision is one.  */
-      if (is_gimple_assign (def_stmt)
-	  && (gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR
-	      && (TYPE_PRECISION (TREE_TYPE (name)) == 1
-	          || comp_code == EQ_EXPR)))
+      if (def_code == BIT_IOR_EXPR
+	  && (TYPE_PRECISION (TREE_TYPE (name)) == 1
+	      || comp_code == EQ_EXPR))
 	{
 	  tree op0 = gimple_assign_rhs1 (def_stmt);
 	  tree op1 = gimple_assign_rhs2 (def_stmt);
 	  retval |= register_edge_assert_for_1 (op0, EQ_EXPR, e, si);
 	  retval |= register_edge_assert_for_1 (op1, EQ_EXPR, e, si);
 	}
+      else if (icode == BIT_IOR_EXPR
+	       && (TYPE_PRECISION (TREE_TYPE (name)) == 1
+		   || comp_code == EQ_EXPR))
+	{
+	  tree op0 = gimple_assign_rhs1 (def_stmt);
+	  tree op1 = gimple_assign_rhs2 (def_stmt);
+	  tree op2 = gimple_assign_rhs3 (def_stmt);
+	  retval |= register_edge_assert_for_1 (op2, EQ_EXPR, e, si);
+	  if (TREE_CODE (op0) == SSA_NAME)
+	    retval |= register_edge_assert_for_2 (op0, e, si, ncode, op0, op1,
+						  true);
+	  if (TREE_CODE (op1) == SSA_NAME)
+	    retval |= register_edge_assert_for_2 (op1, e, si, ncode, op0, op1,
+						  true);
+	}
     }
 
   return retval;
@@ -9114,6 +9195,221 @@ simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
   return true;
 }
 
+/* Check whether a compare which code is RHS_CODE cam be simplified.  OP0 and
+   OP1 are the two operands of the compare and LHS_TYPE is the TREE_TRPE.
+   The logic is the same as it in function simplify_truth_ops_using_ranges.  */
+
+static bool
+can_simplify_ops_using_ranges_p (tree op0, tree op1,
+				 enum tree_code rhs_code, tree lhs_type)
+{
+  bool need_conversion;
+
+  /* We handle only !=/== case here.  */
+  gcc_assert (rhs_code == EQ_EXPR || rhs_code == NE_EXPR);
+
+  if (!op_with_boolean_value_range_p (op0))
+    return false;
+
+  if (!op_with_boolean_value_range_p (op1))
+    return false;
+
+  /* Reduce number of cases to handle to NE_EXPR.  As there is no
+     BIT_XNOR_EXPR we cannot replace A == B with a single statement.  */
+  if (rhs_code == EQ_EXPR)
+    {
+      if (TREE_CODE (op1) == INTEGER_CST)
+        op1 = int_const_binop (BIT_XOR_EXPR, op1, integer_one_node);
+      else
+        return false;
+    }
+
+  need_conversion = !useless_type_conversion_p (lhs_type, TREE_TYPE (op0));
+
+  /* Make sure to not sign-extend a 1-bit 1 when converting the result.  */
+  if (need_conversion
+      && !TYPE_UNSIGNED (TREE_TYPE (op0))
+      && TYPE_PRECISION (TREE_TYPE (op0)) == 1
+      && TYPE_PRECISION (lhs_type) > 1)
+    return false;
+
+  return true;
+}
+
+/* Simplify CCMP STMT to OP.  */
+
+static void
+simplify_ccmp_to_op (gimple_stmt_iterator *gsi, tree op)
+{
+  gimple_assign_set_rhs_from_tree (gsi, op);
+  update_stmt (gsi_stmt (*gsi));
+}
+
+/* Simplify CCMP STMT to a compare wwhich code is CODE.  */
+
+static void
+simplify_ccmp_to_cmp (gimple_stmt_iterator *gsi, gimple stmt,
+		      enum tree_code code)
+{
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  tree rhs2 = gimple_assign_rhs2 (stmt);
+  gimple_assign_set_rhs_with_ops (gsi, code, rhs1, rhs2);
+  update_stmt (gsi_stmt (*gsi));
+}
+
+/* Simplify the second comare of CCMP STMT using ranges if possible.  */
+
+static bool
+simple_ccmp_second_compare (gimple_stmt_iterator *gsi, gimple stmt)
+{
+  bool sop = false;
+  tree val;
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  tree rhs2 = gimple_assign_rhs2 (stmt);
+  enum tree_code rhs_code, code, icode;
+  rhs_code = gimple_assign_rhs_code (stmt);
+  code = get_code_from_ccompare_expr (&icode, rhs_code);
+
+  val = vrp_evaluate_conditional_warnv_with_ops (code, rhs1, rhs2, false, &sop,
+						 NULL);
+  if (val && TREE_CODE (val) == INTEGER_CST)
+    {
+      tree rhs3 = gimple_assign_rhs3 (stmt);
+      if (icode == BIT_AND_EXPR)
+	{
+	  if (integer_zerop (val))
+	    {
+	      /* Simplify CCMP to 0.  */
+	      simplify_ccmp_to_op (gsi, val);
+	    }
+	  else
+	    {
+	      /* Simplify CCMP to rhs3.  */
+	      simplify_ccmp_to_op (gsi, rhs3);
+	    }
+	}
+      else
+	{
+	  gcc_assert (icode == BIT_IOR_EXPR);
+	  if (integer_zerop (val))
+	    {
+	      /* Simplify CCMP to rhs3.  */
+	      simplify_ccmp_to_op (gsi, rhs3);
+	    }
+	  else
+	    {
+	      /* Simplify CCMP to 1.  */
+	      simplify_ccmp_to_op (gsi, val);
+	    }
+	}
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	fprintf (dump_file, "\nCondtional compare is simplified.\n");
+
+      return true;
+    }
+  return false;
+}
+
+/* Simplify CCMP STMT using ranges if possible.  */
+
+static bool
+simplify_ccmp_stmt_using_ranges (gimple_stmt_iterator *gsi)
+{
+  tree rhs1, rhs2, rhs3, type;
+  enum tree_code rhs_code, ncode, icode, def_stmt_code;
+  tree def_stmt_rhs1, def_stmt_rhs2, def_stmt_type, tem;
+  gimple stmt = gsi_stmt (*gsi);
+  gimple def_stmt, cmp;
+  gimple_stmt_iterator cmp_gsi;
+
+  gcc_assert (is_gimple_assign (stmt));
+
+  rhs_code = gimple_assign_rhs_code (stmt);
+  ncode = get_code_from_ccompare_expr (&icode, rhs_code);
+  rhs1 = gimple_assign_rhs1 (stmt);
+  rhs2 = gimple_assign_rhs2 (stmt);
+  rhs3 = gimple_assign_rhs3 (stmt);
+
+  if (TREE_CODE (rhs3) != SSA_NAME
+      ||!is_gimple_assign (SSA_NAME_DEF_STMT (rhs3)))
+    return false;
+
+  def_stmt = SSA_NAME_DEF_STMT (rhs3);
+  def_stmt_code = gimple_assign_rhs_code (def_stmt);
+  def_stmt_rhs1 = gimple_assign_rhs1 (def_stmt);
+
+  if (def_stmt_code == INTEGER_CST)
+    {
+      if (icode == BIT_AND_EXPR)
+	{
+	  if (integer_zerop (def_stmt_rhs1))
+	    {
+	      /* Simplify CCMP to 0.  */
+	      simplify_ccmp_to_op (gsi, rhs3);
+	    }
+	  else
+	    {
+	      /* Simplify CCMP to "rhs1 CMP rhs2".  */
+	      simplify_ccmp_to_cmp (gsi, stmt, ncode);
+	    }
+	}
+      else
+	{
+	  gcc_assert (icode == BIT_IOR_EXPR);
+	  if (integer_zerop (def_stmt_rhs1))
+	    {
+	      /* Simplify CCMP to "rhs1 CMP rhs2".  */
+	      simplify_ccmp_to_cmp (gsi, stmt, ncode);
+	    }
+	  else
+	    {
+	      /* Simplify CCMP to 1.  */
+	      simplify_ccmp_to_op (gsi, rhs2);
+	    }
+	}
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	fprintf (dump_file, "\nCondtional compare is simplified.\n");
+
+      return true;
+    }
+
+   if (simple_ccmp_second_compare (gsi, stmt))
+    return true;
+
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (def_stmt_rhs1))
+      || ((TREE_CODE_CLASS (def_stmt_code) == tcc_comparison)
+	   && !(gimple_assign_rhs_code (def_stmt) == EQ_EXPR
+	        || gimple_assign_rhs_code (def_stmt) == NE_EXPR))
+      || !(ncode == EQ_EXPR || ncode == NE_EXPR))
+    return false;
+
+  def_stmt_type = TREE_TYPE (gimple_assign_lhs (def_stmt));
+  def_stmt_rhs2 = gimple_assign_rhs2 (def_stmt);
+  if ((TREE_CODE_CLASS (def_stmt_code) == tcc_comparison)
+       && !can_simplify_ops_using_ranges_p (def_stmt_rhs1, def_stmt_rhs2,
+					    def_stmt_code, def_stmt_type))
+    return false;
+
+  type = TREE_TYPE (gimple_assign_lhs (stmt));
+  if (!(ncode == EQ_EXPR || ncode == NE_EXPR)
+      || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
+      || !can_simplify_ops_using_ranges_p (rhs1, rhs2, ncode, type))
+    return false;
+
+  /* Simplify conditional compare to bit operator.  And simplify it by
+     simplify_bit_ops_using_ranges.  */
+  tem = make_ssa_name (TREE_TYPE (rhs3), NULL);
+  cmp = gimple_build_assign_with_ops (ncode, tem, rhs1, rhs2);
+  gsi_insert_before (gsi, cmp, GSI_SAME_STMT);
+  cmp_gsi = gsi_for_stmt (cmp);
+  simplify_truth_ops_using_ranges (&cmp_gsi, cmp);
+  gimple_assign_set_rhs_with_ops (gsi, icode, rhs3, tem);
+  update_stmt (gsi_stmt (*gsi));
+  return simplify_bit_ops_using_ranges (gsi, stmt);
+}
+
 /* Simplify STMT using ranges if possible.  */
 
 static bool
@@ -9127,6 +9423,9 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
 
       switch (rhs_code)
 	{
+	CASE_CCMP_ANDIF:
+	CASE_CCMP_ORIF:
+	  return simplify_ccmp_stmt_using_ranges (gsi);
 	case EQ_EXPR:
 	case NE_EXPR:
           /* Transform EQ_EXPR, NE_EXPR into BIT_XOR_EXPR or identity
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp1.c
new file mode 100644
index 0000000..6a5ecba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test (int a, int b)
+{
+  if (a > 0)
+    if (a > 0 && b > 0)
+      return 1;
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\&\&" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp2.c
new file mode 100644
index 0000000..54a05b4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test (int a, int b)
+{
+  if (b > 0)
+    if (a > 0 && b > 0)
+      return 1;
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\&\&" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp3.c
new file mode 100644
index 0000000..66ecbe2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-and-vrp3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test (int a, int b)
+{
+  if (b > 0)
+    if (a > 0)
+      if (a > 0 && b > 0)
+	return 1;
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\&\&" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp1.c
new file mode 100644
index 0000000..6fb5af8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test (int a, int b)
+{
+  if (a > 0)
+    if (a > 0 || b > 0)
+      return 1;
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\\|\\|" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp2.c
new file mode 100644
index 0000000..886d92b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test (int a, int b)
+{
+  if (b > 0)
+    if (a > 0 || b > 0)
+      return 1;
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\\|\\|" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp3.c
new file mode 100644
index 0000000..45a0b5b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ccmp-or-vrp3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int test (int a, int b)
+{
+  if (b > 0)
+    if (a > 0)
+      if (a > 0 || b > 0)
+	return 1;
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\\|\\|" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
