diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d06eee6..f9b207c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2013-04-26  Jeff Law  <law@redhat.com>
+
+	* tree-vrp.c (range_fits_type_p): Move to earlier point in file.
+	(simplify_cond_using_ranges): Generalize code to simplify
+	COND_EXPRs where one argument is a constant and the other
+	is an SSA_NAME created by an integral type conversion.
+
 2013-04-26  Vladimir Makarov  <vmakarov@redhat.com>
 
 	* rtl.h (struct rtx_def): Add comment for field jump.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bbea9fa..6d7839f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2013-04-26  Jeff Law  <law@redhat.com>
+
+	* gcc.dg/tree-ssa/vrp88.c: New test.
+
 2013-04-26  Jakub Jelinek  <jakub@redhat.com>
 
 	PR go/57045
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp88.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp88.c
new file mode 100644
index 0000000..e43bdff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp88.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+
+/* { dg-options "-O2 -fdump-tree-vrp1-details" } */
+
+
+typedef const struct bitmap_head_def *const_bitmap;
+typedef unsigned long BITMAP_WORD;
+typedef struct bitmap_element_def {
+  struct bitmap_element_def *next;
+  BITMAP_WORD bits[((128 + (8 * 8 * 1u) - 1) / (8 * 8 * 1u))];
+} bitmap_element;
+typedef struct bitmap_head_def {
+  bitmap_element *first;
+} bitmap_head;
+unsigned char
+bitmap_single_bit_set_p (const_bitmap a)
+{
+  unsigned long count = 0;
+  const bitmap_element *elt;
+  unsigned ix;
+  if ((!(a)->first))
+    return 0;
+  elt = a->first;
+  if (elt->next != ((void *)0))
+    return 0;
+  for (ix = 0; ix != ((128 + (8 * 8 * 1u) - 1) / (8 * 8 * 1u)); ix++)
+    {
+      count += __builtin_popcountl (elt->bits[ix]);
+      if (count > 1)
+ return 0;
+    }
+  return count == 1;
+}
+
+/* Verify that VRP simplified an "if" statement.  */
+/* { dg-final { scan-tree-dump "Folded into: if.*" "vrp1"} } */
+/* { dg-final { cleanup-tree-dump "vrp1" } } */
+
+
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index cb4a09a..07e3e01 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -8509,6 +8509,57 @@ test_for_singularity (enum tree_code cond_code, tree op0,
   return NULL;
 }
 
+/* Return whether the value range *VR fits in an integer type specified
+   by PRECISION and UNSIGNED_P.  */
+
+static bool
+range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p)
+{
+  tree src_type;
+  unsigned src_precision;
+  double_int tem;
+
+  /* We can only handle integral and pointer types.  */
+  src_type = TREE_TYPE (vr->min);
+  if (!INTEGRAL_TYPE_P (src_type)
+      && !POINTER_TYPE_P (src_type))
+    return false;
+
+  /* An extension is fine unless VR is signed and unsigned_p,
+     and so is an identity transform.  */
+  src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
+  if ((src_precision < precision
+       && !(unsigned_p && !TYPE_UNSIGNED (src_type)))
+      || (src_precision == precision
+	  && TYPE_UNSIGNED (src_type) == unsigned_p))
+    return true;
+
+  /* Now we can only handle ranges with constant bounds.  */
+  if (vr->type != VR_RANGE
+      || TREE_CODE (vr->min) != INTEGER_CST
+      || TREE_CODE (vr->max) != INTEGER_CST)
+    return false;
+
+  /* For sign changes, the MSB of the double_int has to be clear.
+     An unsigned value with its MSB set cannot be represented by
+     a signed double_int, while a negative value cannot be represented
+     by an unsigned double_int.  */
+  if (TYPE_UNSIGNED (src_type) != unsigned_p
+      && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0)
+    return false;
+
+  /* Then we can perform the conversion on both ends and compare
+     the result for equality.  */
+  tem = tree_to_double_int (vr->min).ext (precision, unsigned_p);
+  if (tree_to_double_int (vr->min) != tem)
+    return false;
+  tem = tree_to_double_int (vr->max).ext (precision, unsigned_p);
+  if (tree_to_double_int (vr->max) != tem)
+    return false;
+
+  return true;
+}
+
 /* Simplify a conditional using a relational operator to an equality
    test if the range information indicates only one value can satisfy
    the original conditional.  */
@@ -8590,18 +8641,15 @@ simplify_cond_using_ranges (gimple stmt)
 	}
     }
 
-  /* If we have a comparison of a SSA_NAME boolean against
-     a constant (which obviously must be [0..1]), see if the
-     SSA_NAME was set by a type conversion where the source
-     of the conversion is another SSA_NAME with a range [0..1].
+  /* If we have a comparison of an SSA_NAME (OP0) against a constant,
+     see if OP0 was set by a type conversion where the source of
+     the conversion is another SSA_NAME with a range that fits
+     into the range of OP0's type.
 
-     If so, we can replace the SSA_NAME in the comparison with
-     the RHS of the conversion.  This will often make the type
-     conversion dead code which DCE will clean up.  */
+     If so, the conversion is redundant as the earlier SSA_NAME can be
+     used for the comparison directly if we just massage the constant in the
+     comparison.  */
   if (TREE_CODE (op0) == SSA_NAME
-      && (TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
-	  || (INTEGRAL_TYPE_P (TREE_TYPE (op0))
-	      && TYPE_PRECISION (TREE_TYPE (op0)) == 1))
       && TREE_CODE (op1) == INTEGER_CST)
     {
       gimple def_stmt = SSA_NAME_DEF_STMT (op0);
@@ -8618,8 +8666,9 @@ simplify_cond_using_ranges (gimple stmt)
 	  value_range_t *vr = get_value_range (innerop);
 
 	  if (range_int_cst_p (vr)
-	      && operand_equal_p (vr->min, integer_zero_node, 0)
-	      && operand_equal_p (vr->max, integer_one_node, 0))
+	      && range_fits_type_p (vr,
+				    TYPE_PRECISION (TREE_TYPE (op0)),
+				    TYPE_UNSIGNED (TREE_TYPE (op0))))
 	    {
 	      tree newconst = fold_convert (TREE_TYPE (innerop), op1);
 	      gimple_cond_set_lhs (stmt, innerop);
@@ -8809,57 +8858,6 @@ simplify_conversion_using_ranges (gimple stmt)
   return true;
 }
 
-/* Return whether the value range *VR fits in an integer type specified
-   by PRECISION and UNSIGNED_P.  */
-
-static bool
-range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p)
-{
-  tree src_type;
-  unsigned src_precision;
-  double_int tem;
-
-  /* We can only handle integral and pointer types.  */
-  src_type = TREE_TYPE (vr->min);
-  if (!INTEGRAL_TYPE_P (src_type)
-      && !POINTER_TYPE_P (src_type))
-    return false;
-
-  /* An extension is fine unless VR is signed and unsigned_p,
-     and so is an identity transform.  */
-  src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
-  if ((src_precision < precision
-       && !(unsigned_p && !TYPE_UNSIGNED (src_type)))
-      || (src_precision == precision
-	  && TYPE_UNSIGNED (src_type) == unsigned_p))
-    return true;
-
-  /* Now we can only handle ranges with constant bounds.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
-    return false;
-
-  /* For sign changes, the MSB of the double_int has to be clear.
-     An unsigned value with its MSB set cannot be represented by
-     a signed double_int, while a negative value cannot be represented
-     by an unsigned double_int.  */
-  if (TYPE_UNSIGNED (src_type) != unsigned_p
-      && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0)
-    return false;
-
-  /* Then we can perform the conversion on both ends and compare
-     the result for equality.  */
-  tem = tree_to_double_int (vr->min).ext (precision, unsigned_p);
-  if (tree_to_double_int (vr->min) != tem)
-    return false;
-  tem = tree_to_double_int (vr->max).ext (precision, unsigned_p);
-  if (tree_to_double_int (vr->max) != tem)
-    return false;
-
-  return true;
-}
-
 /* Simplify a conversion from integral SSA name to float in STMT.  */
 
 static bool
