diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 71eb7007f46428ba0bbace4b7dcb3ece743c68d2..8da8006782b8b7262b149171084bcd790a3137de 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2006-01-19  Jeff Law  <law@redhat.com>
+
+	* tree-vrp.c (extract_range_from_assert): Refine the result range
+	if the variable referenced by the ASSERT_EXPR has a range and
+	either the tentative result range or the previous range is a 
+	VR_ANTI_RANGE.
+
 2006-01-19  Richard Sandiford  <richard@codesourcery.com>
 
 	* c-decl.c (add_flexible_array_elts_to_size): Simplify vector accesses.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4266cb0aa4a4dc8563dfb9f6b88c4f29af675e9f..ab86c53c028597459ce53396801151c71f4d5cf2 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2006-01-18  Jeff Law  <law@redhat.com>
+
+	* gcc.dg/tree-ssa/vrp25.c: New test.
+
 2006-01-19  Richard Sandiford  <richard@codesourcery.com>
 
 	* gcc.dg/pr25805.c: Fix misapplied patch.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
new file mode 100644
index 0000000000000000000000000000000000000000..52f9ea2fea54b9c5dcd2137ea4aa7d16fb014112
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp-details" } */
+
+extern void abort ();
+int tree_code_length[100];
+
+blah (int code1)
+{
+  unsigned char D18670;
+
+  if (code1 != 53) goto L0; else goto L1;
+
+L0:
+  abort ();
+
+L1:
+  D18670 = tree_code_length[53];
+  if (D18670 <= 1) goto L2; else goto L3;
+
+L2:
+  abort ();
+
+L3:
+  if (D18670 == 2) goto L4; else goto L5;
+
+L4:
+  abort ();
+
+L5:
+  arf ();
+  if (code1 != 53) goto L6; else goto L7;
+
+L6:
+  abort ();
+
+L7:
+  if (D18670 <= 2) goto L8; else goto L9;
+
+L8:
+  abort ();
+
+L9:
+  return;
+
+}
+
+/* The second test of (code1 != 53) and the test (D18670 <= 2) are
+   both totally subsumed by earlier tests and thus should be folded
+   away using VRP.  */
+/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp" } } */
+/* { dg-final { cleanup-tree-dump "vrp" } } */
+
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index a5028b4d8f59862284c4bdaf568ee9d5c4cfceab..c4a921c50a9aea4c505b9fb2ca8961d5a3c31e3f 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -1048,6 +1048,96 @@ extract_range_from_assert (value_range_t *vr_p, tree expr)
       if (compare_values (var_vr->min, vr_p->min) == 0
 	  && compare_values (var_vr->max, vr_p->max) == 0)
 	set_value_range_to_varying (vr_p);
+      else
+	{
+	  tree min, max, anti_min, anti_max, real_min, real_max;
+
+	  /* We want to compute the logical AND of the two ranges;
+	     there are three cases to consider.
+
+
+	     1. The VR_ANTI_RANGE range is competely within the 
+		VR_RANGE and the endpoints of the ranges are
+		different.  In that case the resulting range
+		should be the VR_ANTI_RANGE.
+
+	     2. The VR_ANTI_RANGE is completely disjoint from
+		the VR_RANGE.  In this case the resulting range
+		should be the VR_RANGE.
+
+	     3. There is some overlap between the VR_ANTI_RANGE
+		and the VR_RANGE.
+
+		3a. If the high limit of the VR_ANTI_RANGE resides
+		    within the VR_RANGE, then the result is a new
+		    VR_RANGE starting at the high limit of the
+		    the VR_ANTI_RANGE + 1 and extending to the
+		    high limit of the original VR_RANGE.
+
+		3b. If the low limit of the VR_ANTI_RANGE resides
+		    within the VR_RANGE, then the result is a new
+		    VR_RANGE starting at the low limit of the original
+		    VR_RANGE and extending to the low limit of the
+		    VR_ANTI_RANGE - 1.  */
+	  if (vr_p->type == VR_ANTI_RANGE)
+	    {
+	      anti_min = vr_p->min;
+	      anti_max = vr_p->max;
+	      real_min = var_vr->min;
+	      real_max = var_vr->max;
+	    }
+	  else
+	    {
+	      anti_min = var_vr->min;
+	      anti_max = var_vr->max;
+	      real_min = vr_p->min;
+	      real_max = vr_p->max;
+	    }
+
+
+	  /* Case 1, VR_ANTI_RANGE completely within VR_RANGE,
+	     not including any endpoints.  */
+	  if (compare_values (anti_max, real_max) == -1
+	      && compare_values (anti_min, real_min) == 1)
+	    {
+	      set_value_range (vr_p, VR_ANTI_RANGE, anti_min,
+			       anti_max, vr_p->equiv);
+	    }
+	  /* Case 2, VR_ANTI_RANGE completely disjoint from
+	     VR_RANGE.  */
+	  else if (compare_values (anti_min, real_max) == 1
+		   || compare_values (anti_max, real_min) == -1)
+	    {
+	      set_value_range (vr_p, VR_RANGE, real_min,
+			       real_max, vr_p->equiv);
+	    }
+	  /* Case 3a, the anti-range extends into the low
+	     part of the real range.  Thus creating a new
+	     low for the real reange.  */
+	  else if ((compare_values (anti_max, real_min) == 1
+		    || compare_values (anti_max, real_min) == 0)
+		   && compare_values (anti_max, real_max) == -1)
+	    {
+	      min = fold_build2 (PLUS_EXPR, TREE_TYPE (var_vr->min),
+				 anti_max,
+				 build_int_cst (TREE_TYPE (var_vr->min), 1));
+	      max = real_max;
+	      set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	    }
+	  /* Case 3b, the anti-range extends into the high
+	     part of the real range.  Thus creating a new
+	     higher for the real reange.  */
+	  else if (compare_values (anti_min, real_min) == 1
+		   && (compare_values (anti_min, real_max) == -1
+		       || compare_values (anti_min, real_max) == 0))
+	    {
+	      max = fold_build2 (MINUS_EXPR, TREE_TYPE (var_vr->min),
+				 anti_min,
+				 build_int_cst (TREE_TYPE (var_vr->min), 1));
+	      min = real_min;
+	      set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
+	    }
+	}
     }
 
   /* Remove names from the equivalence set that have ranges