diff --git a/gcc/function-tests.c b/gcc/function-tests.c
index 65364588734..92f1acf780e 100644
--- a/gcc/function-tests.c
+++ b/gcc/function-tests.c
@@ -580,6 +580,7 @@ test_ranges ()
   function *fun = DECL_STRUCT_FUNCTION (fndecl);
   push_cfun (fun);
   range_tests ();
+  range_op_tests ();
   pop_cfun ();
 }
 
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index f38f02e8d27..bbb2a61ae35 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -3361,7 +3361,6 @@ range_cast (irange &r, tree type)
 
 #if CHECKING_P
 #include "selftest.h"
-#include "stor-layout.h"
 
 namespace selftest
 {
@@ -3369,413 +3368,21 @@ namespace selftest
 #define UINT(N) build_int_cstu (unsigned_type_node, (N))
 #define INT16(N) build_int_cst (short_integer_type_node, (N))
 #define UINT16(N) build_int_cstu (short_unsigned_type_node, (N))
-#define INT64(N) build_int_cstu (long_long_integer_type_node, (N))
-#define UINT64(N) build_int_cstu (long_long_unsigned_type_node, (N))
-#define UINT128(N) build_int_cstu (u128_type, (N))
-#define UCHAR(N) build_int_cstu (unsigned_char_type_node, (N))
 #define SCHAR(N) build_int_cst (signed_char_type_node, (N))
-
-static int_range<3>
-build_range3 (int a, int b, int c, int d, int e, int f)
-{
-  int_range<3> i1 (INT (a), INT (b));
-  int_range<3> i2 (INT (c), INT (d));
-  int_range<3> i3 (INT (e), INT (f));
-  i1.union_ (i2);
-  i1.union_ (i3);
-  return i1;
-}
-
-static void
-range3_tests ()
-{
-  typedef int_range<3> int_range3;
-  int_range3 r0, r1, r2;
-  int_range3 i1, i2, i3;
-
-  // ([10,20] U [5,8]) U [1,3] ==> [1,3][5,8][10,20].
-  r0 = int_range3 (INT (10), INT (20));
-  r1 = int_range3 (INT (5), INT (8));
-  r0.union_ (r1);
-  r1 = int_range3 (INT (1), INT (3));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == build_range3 (1, 3, 5, 8, 10, 20));
-
-  // [1,3][5,8][10,20] U [-5,0] => [-5,3][5,8][10,20].
-  r1 = int_range3 (INT (-5), INT (0));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == build_range3 (-5, 3, 5, 8, 10, 20));
-
-  // [10,20][30,40] U [50,60] ==> [10,20][30,40][50,60].
-  r1 = int_range3 (INT (50), INT (60));
-  r0 = int_range3 (INT (10), INT (20));
-  r0.union_ (int_range3 (INT (30), INT (40)));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == build_range3 (10, 20, 30, 40, 50, 60));
-  // [10,20][30,40][50,60] U [70, 80] ==> [10,20][30,40][50,60][70,80].
-  r1 = int_range3 (INT (70), INT (80));
-  r0.union_ (r1);
-
-  r2 = build_range3 (10, 20, 30, 40, 50, 60);
-  r2.union_ (int_range3 (INT (70), INT (80)));
-  ASSERT_TRUE (r0 == r2);
-
-  // [10,20][30,40][50,60] U [6,35] => [6,40][50,60].
-  r0 = build_range3 (10, 20, 30, 40, 50, 60);
-  r1 = int_range3 (INT (6), INT (35));
-  r0.union_ (r1);
-  r1 = int_range3 (INT (6), INT (40));
-  r1.union_ (int_range3 (INT (50), INT (60)));
-  ASSERT_TRUE (r0 == r1);
-
-  // [10,20][30,40][50,60] U [6,60] => [6,60].
-  r0 = build_range3 (10, 20, 30, 40, 50, 60);
-  r1 = int_range3 (INT (6), INT (60));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == int_range3 (INT (6), INT (60)));
-
-  // [10,20][30,40][50,60] U [6,70] => [6,70].
-  r0 = build_range3 (10, 20, 30, 40, 50, 60);
-  r1 = int_range3 (INT (6), INT (70));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == int_range3 (INT (6), INT (70)));
-
-  // [10,20][30,40][50,60] U [35,70] => [10,20][30,70].
-  r0 = build_range3 (10, 20, 30, 40, 50, 60);
-  r1 = int_range3 (INT (35), INT (70));
-  r0.union_ (r1);
-  r1 = int_range3 (INT (10), INT (20));
-  r1.union_ (int_range3 (INT (30), INT (70)));
-  ASSERT_TRUE (r0 == r1);
-
-  // [10,20][30,40][50,60] U [15,35] => [10,40][50,60].
-  r0 = build_range3 (10, 20, 30, 40, 50, 60);
-  r1 = int_range3 (INT (15), INT (35));
-  r0.union_ (r1);
-  r1 = int_range3 (INT (10), INT (40));
-  r1.union_ (int_range3 (INT (50), INT (60)));
-  ASSERT_TRUE (r0 == r1);
-
-  // [10,20][30,40][50,60] U [35,35] => [10,20][30,40][50,60].
-  r0 = build_range3 (10, 20, 30, 40, 50, 60);
-  r1 = int_range3 (INT (35), INT (35));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == build_range3 (10, 20, 30, 40, 50, 60));
-}
-
-static void
-int_range_max_tests ()
-{
-  int_range_max big;
-  unsigned int nrange;
-
-  // Build a huge multi-range range.
-  for (nrange = 0; nrange < 50; ++nrange)
-    {
-      int_range<1> tmp (INT (nrange*10), INT (nrange*10 + 5));
-      big.union_ (tmp);
-    }
-  ASSERT_TRUE (big.num_pairs () == nrange);
-
-  // Verify that we can copy it without loosing precision.
-  int_range_max copy (big);
-  ASSERT_TRUE (copy.num_pairs () == nrange);
-
-  // Inverting it should produce one more sub-range.
-  big.invert ();
-  ASSERT_TRUE (big.num_pairs () == nrange + 1);
-
-  int_range<1> tmp (INT (5), INT (37));
-  big.intersect (tmp);
-  ASSERT_TRUE (big.num_pairs () == 4);
-
-  // Test that [10,10][20,20] does NOT contain 15.
-  {
-    int_range_max i1 (build_int_cst (integer_type_node, 10),
-		      build_int_cst (integer_type_node, 10));
-    int_range_max i2 (build_int_cst (integer_type_node, 20),
-		      build_int_cst (integer_type_node, 20));
-    i1.union_ (i2);
-    ASSERT_FALSE (i1.contains_p (build_int_cst (integer_type_node, 15)));
-  }
-
-}
-
-static void
-multi_precision_range_tests ()
-{
-  // Test truncating copy to int_range<1>.
-  int_range<3> big = build_range3 (10, 20, 30, 40, 50, 60);
-  int_range<1> small = big;
-  ASSERT_TRUE (small == int_range<1> (INT (10), INT (60)));
-
-  // Test truncating copy to int_range<2>.
-  int_range<2> medium = big;
-  ASSERT_TRUE (!medium.undefined_p ());
-
-  // Test that a truncating copy of [MIN,20][22,40][80,MAX]
-  // ends up as a conservative anti-range of ~[21,21].
-  big = int_range<3> (vrp_val_min (integer_type_node), INT (20));
-  big.union_ (int_range<1> (INT (22), INT (40)));
-  big.union_ (int_range<1> (INT (80), vrp_val_max (integer_type_node)));
-  small = big;
-  ASSERT_TRUE (small == int_range<1> (INT (21), INT (21), VR_ANTI_RANGE));
-
-  // Copying a legacy symbolic to an int_range should normalize the
-  // symbolic at copy time.
-  {
-    tree ssa = make_ssa_name (integer_type_node);
-    value_range legacy_range (ssa, INT (25));
-    int_range<2> copy = legacy_range;
-    ASSERT_TRUE (copy == int_range<2>  (vrp_val_min (integer_type_node),
-					INT (25)));
-
-    // Test that copying ~[abc_23, abc_23] to a multi-range yields varying.
-    legacy_range = value_range (ssa, ssa, VR_ANTI_RANGE);
-    copy = legacy_range;
-    ASSERT_TRUE (copy.varying_p ());
-  }
-
-  range3_tests ();
-}
+#define UCHAR(N) build_int_cstu (unsigned_char_type_node, (N))
 
 static void
-operator_tests ()
-{
-  tree min = vrp_val_min (integer_type_node);
-  tree max = vrp_val_max (integer_type_node);
-  tree tiny = fold_build2 (PLUS_EXPR, integer_type_node, min,
-			   build_one_cst (integer_type_node));
-  int_range_max res;
-  int_range_max i1 (tiny, max);
-  int_range_max i2 (build_int_cst (integer_type_node, 255),
-		    build_int_cst (integer_type_node, 255));
-
-  // [MIN+1, MAX] = OP1 & 255: OP1 is VARYING
-  op_bitwise_and.op1_range (res, integer_type_node, i1, i2);
-  ASSERT_TRUE (res == int_range<1> (integer_type_node));
-
-  // VARYING = OP1 & 255: OP1 is VARYING
-  i1 = int_range<1> (integer_type_node);
-  op_bitwise_and.op1_range (res, integer_type_node, i1, i2);
-  ASSERT_TRUE (res == int_range<1> (integer_type_node));
-
-  // Test that 0x808.... & 0x8.... still contains 0x8....
-  // for a large set of numbers.
-  {
-    tree big_type = long_long_unsigned_type_node;
-    // big_num = 0x808,0000,0000,0000
-    tree big_num = fold_build2 (LSHIFT_EXPR, big_type,
-				build_int_cst (big_type, 0x808),
-				build_int_cst (big_type, 48));
-    op_bitwise_and.fold_range (res, big_type,
-			       int_range <1> (big_type),
-			       int_range <1> (big_num, big_num));
-    // val = 0x8,0000,0000,0000
-    tree val = fold_build2 (LSHIFT_EXPR, big_type,
-			    build_int_cst (big_type, 0x8),
-			    build_int_cst (big_type, 48));
-    ASSERT_TRUE (res.contains_p (val));
-  }
-
-  // unsigned: [3, MAX] = OP1 >> 1
-  {
-    int_range_max lhs (build_int_cst (unsigned_type_node, 3),
-		       TYPE_MAX_VALUE (unsigned_type_node));
-    int_range_max one (build_one_cst (unsigned_type_node),
-		       build_one_cst (unsigned_type_node));
-    int_range_max op1;
-    op_rshift.op1_range (op1, unsigned_type_node, lhs, one);
-    ASSERT_FALSE (op1.contains_p (UINT (3)));
-  }
-
-  // signed: [3, MAX] = OP1 >> 1
-  {
-    int_range_max lhs (INT (3), TYPE_MAX_VALUE (integer_type_node));
-    int_range_max one (INT (1), INT (1));
-    int_range_max op1;
-    op_rshift.op1_range (op1, integer_type_node, lhs, one);
-    ASSERT_FALSE (op1.contains_p (INT (-2)));
-  }
-
-  // This is impossible, so OP1 should be [].
-  // signed: [MIN, MIN] = OP1 >> 1
-  {
-    int_range_max lhs (TYPE_MIN_VALUE (integer_type_node),
-		       TYPE_MIN_VALUE (integer_type_node));
-    int_range_max one (INT (1), INT (1));
-    int_range_max op1;
-    op_rshift.op1_range (op1, integer_type_node, lhs, one);
-    ASSERT_TRUE (op1.undefined_p ());
-  }
-
-  // signed: ~[-1] = OP1 >> 31
-  if (TYPE_PRECISION (integer_type_node) > 31)
-    {
-      int_range_max lhs (INT (-1), INT (-1), VR_ANTI_RANGE);
-      int_range_max shift (INT (31), INT (31));
-      int_range_max op1;
-      op_rshift.op1_range (op1, integer_type_node, lhs, shift);
-      int_range_max negatives = range_negatives (integer_type_node);
-      negatives.intersect (op1);
-      ASSERT_TRUE (negatives.undefined_p ());
-    }
-
-  if (TYPE_PRECISION (unsigned_type_node) > 31)
-    {
-      // unsigned VARYING = op1 << 1 should be VARYING.
-      int_range<2> lhs (unsigned_type_node);
-      int_range<2> shift (INT (1), INT (1));
-      int_range_max op1;
-      op_lshift.op1_range (op1, unsigned_type_node, lhs, shift);
-      ASSERT_TRUE (op1.varying_p ());
-
-      // 0 = op1 << 1  should be [0,0], [0x8000000, 0x8000000].
-      int_range<2> zero (UINT (0), UINT (0));
-      op_lshift.op1_range (op1, unsigned_type_node, zero, shift);
-      ASSERT_TRUE (op1.num_pairs () == 2);
-      // Remove the [0,0] range.
-      op1.intersect (zero);
-      ASSERT_TRUE (op1.num_pairs () == 1);
-      //  op1 << 1   should be [0x8000,0x8000] << 1,
-      //  which should result in [0,0].
-      int_range_max result;
-      op_lshift.fold_range (result, unsigned_type_node, op1, shift);
-      ASSERT_TRUE (result == zero);
-    }
-  // signed VARYING = op1 << 1 should be VARYING.
-  if (TYPE_PRECISION (integer_type_node) > 31)
-    {
-      // unsigned VARYING = op1 << 1  hould be VARYING.
-      int_range<2> lhs (integer_type_node);
-      int_range<2> shift (INT (1), INT (1));
-      int_range_max op1;
-      op_lshift.op1_range (op1, integer_type_node, lhs, shift);
-      ASSERT_TRUE (op1.varying_p ());
-
-      //  0 = op1 << 1  should be [0,0], [0x8000000, 0x8000000].
-      int_range<2> zero (INT (0), INT (0));
-      op_lshift.op1_range (op1, integer_type_node, zero, shift);
-      ASSERT_TRUE (op1.num_pairs () == 2);
-      // Remove the [0,0] range.
-      op1.intersect (zero);
-      ASSERT_TRUE (op1.num_pairs () == 1);
-      //  op1 << 1   shuould be [0x8000,0x8000] << 1,
-      //  which should result in [0,0].
-      int_range_max result;
-      op_lshift.fold_range (result, unsigned_type_node, op1, shift);
-      ASSERT_TRUE (result == zero);
-    }
-}
-
-// Run all of the selftests within this file.
-
-void
-range_tests ()
+range_op_cast_tests ()
 {
-  tree u128_type = build_nonstandard_integer_type (128, /*unsigned=*/1);
-  int_range<1> i1, i2, i3;
-  int_range<1> r0, r1, rold;
-
-  // Test 1-bit signed integer union.
-  // [-1,-1] U [0,0] = VARYING.
-  tree one_bit_type = build_nonstandard_integer_type (1, 0);
-  tree one_bit_min = vrp_val_min (one_bit_type);
-  tree one_bit_max = vrp_val_max (one_bit_type);
-  {
-    int_range<2> min (one_bit_min, one_bit_min);
-    int_range<2> max (one_bit_max, one_bit_max);
-    max.union_ (min);
-    ASSERT_TRUE (max.varying_p ());
-  }
-
-  // Test inversion of 1-bit signed integers.
-  {
-    int_range<2> min (one_bit_min, one_bit_min);
-    int_range<2> max (one_bit_max, one_bit_max);
-    int_range<2> t;
-    t = min;
-    t.invert ();
-    ASSERT_TRUE (t == max);
-    t = max;
-    t.invert ();
-    ASSERT_TRUE (t == min);
-  }
-
-  // Test that NOT(255) is [0..254] in 8-bit land.
-  int_range<1> not_255 (UCHAR (255), UCHAR (255), VR_ANTI_RANGE);
-  ASSERT_TRUE (not_255 == int_range<1> (UCHAR (0), UCHAR (254)));
-
-  // Test that NOT(0) is [1..255] in 8-bit land.
-  int_range<1> not_zero = range_nonzero (unsigned_char_type_node);
-  ASSERT_TRUE (not_zero == int_range<1> (UCHAR (1), UCHAR (255)));
-
-  // Check that [0,127][0x..ffffff80,0x..ffffff]
-  //  => ~[128, 0x..ffffff7f].
-  r0 = int_range<1> (UINT128 (0), UINT128 (127));
-  tree high = build_minus_one_cst (u128_type);
-  // low = -1 - 127 => 0x..ffffff80.
-  tree low = fold_build2 (MINUS_EXPR, u128_type, high, UINT128(127));
-  r1 = int_range<1> (low, high); // [0x..ffffff80, 0x..ffffffff]
-  // r0 = [0,127][0x..ffffff80,0x..fffffff].
-  r0.union_ (r1);
-  // r1 = [128, 0x..ffffff7f].
-  r1 = int_range<1> (UINT128(128),
-		     fold_build2 (MINUS_EXPR, u128_type,
-				  build_minus_one_cst (u128_type),
-				  UINT128(128)));
-  r0.invert ();
-  ASSERT_TRUE (r0 == r1);
-
+  int_range<1> r0, r1, r2, rold;
   r0.set_varying (integer_type_node);
-  tree minint = wide_int_to_tree (integer_type_node, r0.lower_bound ());
   tree maxint = wide_int_to_tree (integer_type_node, r0.upper_bound ());
 
+  // If a range is in any way outside of the range for the converted
+  // to range, default to the range for the new type.
   r0.set_varying (short_integer_type_node);
   tree minshort = wide_int_to_tree (short_integer_type_node, r0.lower_bound ());
   tree maxshort = wide_int_to_tree (short_integer_type_node, r0.upper_bound ());
-
-  r0.set_varying (unsigned_type_node);
-  tree maxuint = wide_int_to_tree (unsigned_type_node, r0.upper_bound ());
-
-  // Check that ~[0,5] => [6,MAX] for unsigned int.
-  r0 = int_range<1> (UINT (0), UINT (5));
-  r0.invert ();
-  ASSERT_TRUE (r0 == int_range<1> (UINT(6), maxuint));
-
-  // Check that ~[10,MAX] => [0,9] for unsigned int.
-  r0 = int_range<1> (UINT(10), maxuint);
-  r0.invert ();
-  ASSERT_TRUE (r0 == int_range<1> (UINT (0), UINT (9)));
-
-  // Check that ~[0,5] => [6,MAX] for unsigned 128-bit numbers.
-  r0 = int_range<1> (UINT128 (0), UINT128 (5), VR_ANTI_RANGE);
-  r1 = int_range<1> (UINT128(6), build_minus_one_cst (u128_type));
-  ASSERT_TRUE (r0 == r1);
-
-  // Check that [~5] is really [-MIN,4][6,MAX].
-  r0 = int_range<1> (INT (5), INT (5), VR_ANTI_RANGE);
-  r1 = int_range<1> (minint, INT (4));
-  r1.union_ (int_range<1> (INT (6), maxint));
-  ASSERT_FALSE (r1.undefined_p ());
-  ASSERT_TRUE (r0 == r1);
-
-  r1 = int_range<1> (INT (5), INT (5));
-  int_range<1> r2 (r1);
-  ASSERT_TRUE (r1 == r2);
-
-  r1 = int_range<1> (INT (5), INT (10));
-
-  r1 = int_range<1> (integer_type_node,
-		     wi::to_wide (INT (5)), wi::to_wide (INT (10)));
-  ASSERT_TRUE (r1.contains_p (INT (7)));
-
-  r1 = int_range<1> (SCHAR (0), SCHAR (20));
-  ASSERT_TRUE (r1.contains_p (SCHAR(15)));
-  ASSERT_FALSE (r1.contains_p (SCHAR(300)));
-
-  // If a range is in any way outside of the range for the converted
-  // to range, default to the range for the new type.
   if (TYPE_PRECISION (TREE_TYPE (maxint))
       > TYPE_PRECISION (short_integer_type_node))
     {
@@ -3865,25 +3472,6 @@ range_tests ()
 	       TYPE_MAX_VALUE (short_unsigned_type_node));
   ASSERT_TRUE (r0 == r1);
 
-  // NOT([10,20]) ==> [-MIN,9][21,MAX].
-  r0 = r1 = int_range<1> (INT (10), INT (20));
-  r2 = int_range<1> (minint, INT(9));
-  r2.union_ (int_range<1> (INT(21), maxint));
-  ASSERT_FALSE (r2.undefined_p ());
-  r1.invert ();
-  ASSERT_TRUE (r1 == r2);
-  // Test that NOT(NOT(x)) == x.
-  r2.invert ();
-  ASSERT_TRUE (r0 == r2);
-
-  // Test that booleans and their inverse work as expected.
-  r0 = range_zero (boolean_type_node);
-  ASSERT_TRUE (r0 == int_range<1> (build_zero_cst (boolean_type_node),
-				   build_zero_cst (boolean_type_node)));
-  r0.invert ();
-  ASSERT_TRUE (r0 == int_range<1> (build_one_cst (boolean_type_node),
-				   build_one_cst (boolean_type_node)));
-
   // Casting NONZERO to a narrower type will wrap/overflow so
   // it's just the entire range for the narrower type.
   //
@@ -3910,84 +3498,153 @@ range_tests ()
   r2 = int_range<1> (INT (1), INT (32767));
   r1.union_ (r2);
   ASSERT_TRUE (r0 == r1);
+}
 
-  // Make sure NULL and non-NULL of pointer types work, and that
-  // inverses of them are consistent.
-  tree voidp = build_pointer_type (void_type_node);
-  r0 = range_zero (voidp);
-  r1 = r0;
-  r0.invert ();
-  r0.invert ();
-  ASSERT_TRUE (r0 == r1);
+static void
+range_op_lshift_tests ()
+{
+  // Test that 0x808.... & 0x8.... still contains 0x8....
+  // for a large set of numbers.
+  {
+    int_range_max res;
+    tree big_type = long_long_unsigned_type_node;
+    // big_num = 0x808,0000,0000,0000
+    tree big_num = fold_build2 (LSHIFT_EXPR, big_type,
+				build_int_cst (big_type, 0x808),
+				build_int_cst (big_type, 48));
+    op_bitwise_and.fold_range (res, big_type,
+			       int_range <1> (big_type),
+			       int_range <1> (big_num, big_num));
+    // val = 0x8,0000,0000,0000
+    tree val = fold_build2 (LSHIFT_EXPR, big_type,
+			    build_int_cst (big_type, 0x8),
+			    build_int_cst (big_type, 48));
+    ASSERT_TRUE (res.contains_p (val));
+  }
 
-  // [10,20] U [15, 30] => [10, 30].
-  r0 = int_range<1> (INT (10), INT (20));
-  r1 = int_range<1> (INT (15), INT (30));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == int_range<1> (INT (10), INT (30)));
-
-  // [15,40] U [] => [15,40].
-  r0 = int_range<1> (INT (15), INT (40));
-  r1.set_undefined ();
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == int_range<1> (INT (15), INT (40)));
-
-  // [10,20] U [10,10] => [10,20].
-  r0 = int_range<1> (INT (10), INT (20));
-  r1 = int_range<1> (INT (10), INT (10));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == int_range<1> (INT (10), INT (20)));
-
-  // [10,20] U [9,9] => [9,20].
-  r0 = int_range<1> (INT (10), INT (20));
-  r1 = int_range<1> (INT (9), INT (9));
-  r0.union_ (r1);
-  ASSERT_TRUE (r0 == int_range<1> (INT (9), INT (20)));
-
-  // [10,20] ^ [15,30] => [15,20].
-  r0 = int_range<1> (INT (10), INT (20));
-  r1 = int_range<1> (INT (15), INT (30));
-  r0.intersect (r1);
-  ASSERT_TRUE (r0 == int_range<1> (INT (15), INT (20)));
-
-  // Test the internal sanity of wide_int's wrt HWIs.
-  ASSERT_TRUE (wi::max_value (TYPE_PRECISION (boolean_type_node),
-			      TYPE_SIGN (boolean_type_node))
-	       == wi::uhwi (1, TYPE_PRECISION (boolean_type_node)));
-
-  // Test zero_p().
-  r0 = int_range<1> (INT (0), INT (0));
-  ASSERT_TRUE (r0.zero_p ());
-
-  // Test nonzero_p().
-  r0 = int_range<1> (INT (0), INT (0));
-  r0.invert ();
-  ASSERT_TRUE (r0.nonzero_p ());
-
-  // test legacy interaction
-  // r0 = ~[1,1]
-  r0 = int_range<1> (UINT (1), UINT (1), VR_ANTI_RANGE);
-  // r1 = ~[3,3]
-  r1 = int_range<1> (UINT (3), UINT (3), VR_ANTI_RANGE);
-
-  // vv = [0,0][2,2][4, MAX]
-  int_range<3> vv = r0;
-  vv.intersect (r1);
-
-  ASSERT_TRUE (vv.contains_p (UINT (2)));
-  ASSERT_TRUE (vv.num_pairs () == 3);
-
-  // create r0 as legacy [1,1]
-  r0 = int_range<1> (UINT (1), UINT (1));
-  // And union it with  [0,0][2,2][4,MAX] multi range
-  r0.union_ (vv);
-  // The result should be [0,2][4,MAX], or ~[3,3]  but it must contain 2
-  ASSERT_TRUE (r0.contains_p (UINT (2)));
-
-
-  multi_precision_range_tests ();
-  int_range_max_tests ();
-  operator_tests ();
+  if (TYPE_PRECISION (unsigned_type_node) > 31)
+    {
+      // unsigned VARYING = op1 << 1 should be VARYING.
+      int_range<2> lhs (unsigned_type_node);
+      int_range<2> shift (INT (1), INT (1));
+      int_range_max op1;
+      op_lshift.op1_range (op1, unsigned_type_node, lhs, shift);
+      ASSERT_TRUE (op1.varying_p ());
+
+      // 0 = op1 << 1  should be [0,0], [0x8000000, 0x8000000].
+      int_range<2> zero (UINT (0), UINT (0));
+      op_lshift.op1_range (op1, unsigned_type_node, zero, shift);
+      ASSERT_TRUE (op1.num_pairs () == 2);
+      // Remove the [0,0] range.
+      op1.intersect (zero);
+      ASSERT_TRUE (op1.num_pairs () == 1);
+      //  op1 << 1   should be [0x8000,0x8000] << 1,
+      //  which should result in [0,0].
+      int_range_max result;
+      op_lshift.fold_range (result, unsigned_type_node, op1, shift);
+      ASSERT_TRUE (result == zero);
+    }
+  // signed VARYING = op1 << 1 should be VARYING.
+  if (TYPE_PRECISION (integer_type_node) > 31)
+    {
+      // unsigned VARYING = op1 << 1  hould be VARYING.
+      int_range<2> lhs (integer_type_node);
+      int_range<2> shift (INT (1), INT (1));
+      int_range_max op1;
+      op_lshift.op1_range (op1, integer_type_node, lhs, shift);
+      ASSERT_TRUE (op1.varying_p ());
+
+      //  0 = op1 << 1  should be [0,0], [0x8000000, 0x8000000].
+      int_range<2> zero (INT (0), INT (0));
+      op_lshift.op1_range (op1, integer_type_node, zero, shift);
+      ASSERT_TRUE (op1.num_pairs () == 2);
+      // Remove the [0,0] range.
+      op1.intersect (zero);
+      ASSERT_TRUE (op1.num_pairs () == 1);
+      //  op1 << 1   shuould be [0x8000,0x8000] << 1,
+      //  which should result in [0,0].
+      int_range_max result;
+      op_lshift.fold_range (result, unsigned_type_node, op1, shift);
+      ASSERT_TRUE (result == zero);
+    }
+}
+
+static void
+range_op_rshift_tests ()
+{
+  // unsigned: [3, MAX] = OP1 >> 1
+  {
+    int_range_max lhs (build_int_cst (unsigned_type_node, 3),
+		       TYPE_MAX_VALUE (unsigned_type_node));
+    int_range_max one (build_one_cst (unsigned_type_node),
+		       build_one_cst (unsigned_type_node));
+    int_range_max op1;
+    op_rshift.op1_range (op1, unsigned_type_node, lhs, one);
+    ASSERT_FALSE (op1.contains_p (UINT (3)));
+  }
+
+  // signed: [3, MAX] = OP1 >> 1
+  {
+    int_range_max lhs (INT (3), TYPE_MAX_VALUE (integer_type_node));
+    int_range_max one (INT (1), INT (1));
+    int_range_max op1;
+    op_rshift.op1_range (op1, integer_type_node, lhs, one);
+    ASSERT_FALSE (op1.contains_p (INT (-2)));
+  }
+
+  // This is impossible, so OP1 should be [].
+  // signed: [MIN, MIN] = OP1 >> 1
+  {
+    int_range_max lhs (TYPE_MIN_VALUE (integer_type_node),
+		       TYPE_MIN_VALUE (integer_type_node));
+    int_range_max one (INT (1), INT (1));
+    int_range_max op1;
+    op_rshift.op1_range (op1, integer_type_node, lhs, one);
+    ASSERT_TRUE (op1.undefined_p ());
+  }
+
+  // signed: ~[-1] = OP1 >> 31
+  if (TYPE_PRECISION (integer_type_node) > 31)
+    {
+      int_range_max lhs (INT (-1), INT (-1), VR_ANTI_RANGE);
+      int_range_max shift (INT (31), INT (31));
+      int_range_max op1;
+      op_rshift.op1_range (op1, integer_type_node, lhs, shift);
+      int_range_max negatives = range_negatives (integer_type_node);
+      negatives.intersect (op1);
+      ASSERT_TRUE (negatives.undefined_p ());
+    }
+}
+
+static void
+range_op_bitwise_and_tests ()
+{
+  int_range_max res;
+  tree min = vrp_val_min (integer_type_node);
+  tree max = vrp_val_max (integer_type_node);
+  tree tiny = fold_build2 (PLUS_EXPR, integer_type_node, min,
+			   build_one_cst (integer_type_node));
+  int_range_max i1 (tiny, max);
+  int_range_max i2 (build_int_cst (integer_type_node, 255),
+		    build_int_cst (integer_type_node, 255));
+
+  // [MIN+1, MAX] = OP1 & 255: OP1 is VARYING
+  op_bitwise_and.op1_range (res, integer_type_node, i1, i2);
+  ASSERT_TRUE (res == int_range<1> (integer_type_node));
+
+  // VARYING = OP1 & 255: OP1 is VARYING
+  i1 = int_range<1> (integer_type_node);
+  op_bitwise_and.op1_range (res, integer_type_node, i1, i2);
+  ASSERT_TRUE (res == int_range<1> (integer_type_node));
+}
+
+void
+range_op_tests ()
+{
+  range_op_rshift_tests ();
+  range_op_lshift_tests ();
+  range_op_bitwise_and_tests ();
+  range_op_cast_tests ();
 }
 
 } // namespace selftest
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 6c6c7f28675..963e074b4d2 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -248,6 +248,7 @@ extern void ordered_hash_map_tests_cc_tests ();
 extern void predict_c_tests ();
 extern void pretty_print_c_tests ();
 extern void range_tests ();
+extern void range_op_tests ();
 extern void read_rtl_function_c_tests ();
 extern void rtl_tests_c_tests ();
 extern void sbitmap_c_tests ();
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 5827e812216..1ce928b9d97 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -2090,3 +2090,383 @@ DEFINE_INT_RANGE_INSTANCE(2)
 DEFINE_INT_RANGE_INSTANCE(3)
 DEFINE_INT_RANGE_INSTANCE(255)
 DEFINE_INT_RANGE_GC_STUBS(1)
+
+#if CHECKING_P
+#include "selftest.h"
+
+namespace selftest
+{
+#define INT(N) build_int_cst (integer_type_node, (N))
+#define UINT(N) build_int_cstu (unsigned_type_node, (N))
+#define UINT128(N) build_int_cstu (u128_type, (N))
+#define UCHAR(N) build_int_cstu (unsigned_char_type_node, (N))
+#define SCHAR(N) build_int_cst (signed_char_type_node, (N))
+
+static int_range<3>
+build_range3 (int a, int b, int c, int d, int e, int f)
+{
+  int_range<3> i1 (INT (a), INT (b));
+  int_range<3> i2 (INT (c), INT (d));
+  int_range<3> i3 (INT (e), INT (f));
+  i1.union_ (i2);
+  i1.union_ (i3);
+  return i1;
+}
+
+static void
+range_tests_irange3 ()
+{
+  typedef int_range<3> int_range3;
+  int_range3 r0, r1, r2;
+  int_range3 i1, i2, i3;
+
+  // ([10,20] U [5,8]) U [1,3] ==> [1,3][5,8][10,20].
+  r0 = int_range3 (INT (10), INT (20));
+  r1 = int_range3 (INT (5), INT (8));
+  r0.union_ (r1);
+  r1 = int_range3 (INT (1), INT (3));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (1, 3, 5, 8, 10, 20));
+
+  // [1,3][5,8][10,20] U [-5,0] => [-5,3][5,8][10,20].
+  r1 = int_range3 (INT (-5), INT (0));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (-5, 3, 5, 8, 10, 20));
+
+  // [10,20][30,40] U [50,60] ==> [10,20][30,40][50,60].
+  r1 = int_range3 (INT (50), INT (60));
+  r0 = int_range3 (INT (10), INT (20));
+  r0.union_ (int_range3 (INT (30), INT (40)));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (10, 20, 30, 40, 50, 60));
+  // [10,20][30,40][50,60] U [70, 80] ==> [10,20][30,40][50,60][70,80].
+  r1 = int_range3 (INT (70), INT (80));
+  r0.union_ (r1);
+
+  r2 = build_range3 (10, 20, 30, 40, 50, 60);
+  r2.union_ (int_range3 (INT (70), INT (80)));
+  ASSERT_TRUE (r0 == r2);
+
+  // [10,20][30,40][50,60] U [6,35] => [6,40][50,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = int_range3 (INT (6), INT (35));
+  r0.union_ (r1);
+  r1 = int_range3 (INT (6), INT (40));
+  r1.union_ (int_range3 (INT (50), INT (60)));
+  ASSERT_TRUE (r0 == r1);
+
+  // [10,20][30,40][50,60] U [6,60] => [6,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = int_range3 (INT (6), INT (60));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == int_range3 (INT (6), INT (60)));
+
+  // [10,20][30,40][50,60] U [6,70] => [6,70].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = int_range3 (INT (6), INT (70));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == int_range3 (INT (6), INT (70)));
+
+  // [10,20][30,40][50,60] U [35,70] => [10,20][30,70].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = int_range3 (INT (35), INT (70));
+  r0.union_ (r1);
+  r1 = int_range3 (INT (10), INT (20));
+  r1.union_ (int_range3 (INT (30), INT (70)));
+  ASSERT_TRUE (r0 == r1);
+
+  // [10,20][30,40][50,60] U [15,35] => [10,40][50,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = int_range3 (INT (15), INT (35));
+  r0.union_ (r1);
+  r1 = int_range3 (INT (10), INT (40));
+  r1.union_ (int_range3 (INT (50), INT (60)));
+  ASSERT_TRUE (r0 == r1);
+
+  // [10,20][30,40][50,60] U [35,35] => [10,20][30,40][50,60].
+  r0 = build_range3 (10, 20, 30, 40, 50, 60);
+  r1 = int_range3 (INT (35), INT (35));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == build_range3 (10, 20, 30, 40, 50, 60));
+}
+
+static void
+range_tests_int_range_max ()
+{
+  int_range_max big;
+  unsigned int nrange;
+
+  // Build a huge multi-range range.
+  for (nrange = 0; nrange < 50; ++nrange)
+    {
+      int_range<1> tmp (INT (nrange*10), INT (nrange*10 + 5));
+      big.union_ (tmp);
+    }
+  ASSERT_TRUE (big.num_pairs () == nrange);
+
+  // Verify that we can copy it without loosing precision.
+  int_range_max copy (big);
+  ASSERT_TRUE (copy.num_pairs () == nrange);
+
+  // Inverting it should produce one more sub-range.
+  big.invert ();
+  ASSERT_TRUE (big.num_pairs () == nrange + 1);
+
+  int_range<1> tmp (INT (5), INT (37));
+  big.intersect (tmp);
+  ASSERT_TRUE (big.num_pairs () == 4);
+
+  // Test that [10,10][20,20] does NOT contain 15.
+  {
+    int_range_max i1 (build_int_cst (integer_type_node, 10),
+		      build_int_cst (integer_type_node, 10));
+    int_range_max i2 (build_int_cst (integer_type_node, 20),
+		      build_int_cst (integer_type_node, 20));
+    i1.union_ (i2);
+    ASSERT_FALSE (i1.contains_p (build_int_cst (integer_type_node, 15)));
+  }
+}
+
+static void
+range_tests_legacy ()
+{
+  // Test truncating copy to int_range<1>.
+  int_range<3> big = build_range3 (10, 20, 30, 40, 50, 60);
+  int_range<1> small = big;
+  ASSERT_TRUE (small == int_range<1> (INT (10), INT (60)));
+
+  // Test truncating copy to int_range<2>.
+  int_range<2> medium = big;
+  ASSERT_TRUE (!medium.undefined_p ());
+
+  // Test that a truncating copy of [MIN,20][22,40][80,MAX]
+  // ends up as a conservative anti-range of ~[21,21].
+  big = int_range<3> (vrp_val_min (integer_type_node), INT (20));
+  big.union_ (int_range<1> (INT (22), INT (40)));
+  big.union_ (int_range<1> (INT (80), vrp_val_max (integer_type_node)));
+  small = big;
+  ASSERT_TRUE (small == int_range<1> (INT (21), INT (21), VR_ANTI_RANGE));
+
+  // Copying a legacy symbolic to an int_range should normalize the
+  // symbolic at copy time.
+  {
+    tree ssa = make_ssa_name (integer_type_node);
+    value_range legacy_range (ssa, INT (25));
+    int_range<2> copy = legacy_range;
+    ASSERT_TRUE (copy == int_range<2>  (vrp_val_min (integer_type_node),
+					INT (25)));
+
+    // Test that copying ~[abc_23, abc_23] to a multi-range yields varying.
+    legacy_range = value_range (ssa, ssa, VR_ANTI_RANGE);
+    copy = legacy_range;
+    ASSERT_TRUE (copy.varying_p ());
+  }
+}
+
+static void
+range_tests_misc ()
+{
+  tree u128_type = build_nonstandard_integer_type (128, /*unsigned=*/1);
+  int_range<1> i1, i2, i3;
+  int_range<1> r0, r1, rold;
+
+  // Test 1-bit signed integer union.
+  // [-1,-1] U [0,0] = VARYING.
+  tree one_bit_type = build_nonstandard_integer_type (1, 0);
+  tree one_bit_min = vrp_val_min (one_bit_type);
+  tree one_bit_max = vrp_val_max (one_bit_type);
+  {
+    int_range<2> min (one_bit_min, one_bit_min);
+    int_range<2> max (one_bit_max, one_bit_max);
+    max.union_ (min);
+    ASSERT_TRUE (max.varying_p ());
+  }
+
+  // Test inversion of 1-bit signed integers.
+  {
+    int_range<2> min (one_bit_min, one_bit_min);
+    int_range<2> max (one_bit_max, one_bit_max);
+    int_range<2> t;
+    t = min;
+    t.invert ();
+    ASSERT_TRUE (t == max);
+    t = max;
+    t.invert ();
+    ASSERT_TRUE (t == min);
+  }
+
+  // Test that NOT(255) is [0..254] in 8-bit land.
+  int_range<1> not_255 (UCHAR (255), UCHAR (255), VR_ANTI_RANGE);
+  ASSERT_TRUE (not_255 == int_range<1> (UCHAR (0), UCHAR (254)));
+
+  // Test that NOT(0) is [1..255] in 8-bit land.
+  int_range<1> not_zero = range_nonzero (unsigned_char_type_node);
+  ASSERT_TRUE (not_zero == int_range<1> (UCHAR (1), UCHAR (255)));
+
+  // Check that [0,127][0x..ffffff80,0x..ffffff]
+  //  => ~[128, 0x..ffffff7f].
+  r0 = int_range<1> (UINT128 (0), UINT128 (127));
+  tree high = build_minus_one_cst (u128_type);
+  // low = -1 - 127 => 0x..ffffff80.
+  tree low = fold_build2 (MINUS_EXPR, u128_type, high, UINT128(127));
+  r1 = int_range<1> (low, high); // [0x..ffffff80, 0x..ffffffff]
+  // r0 = [0,127][0x..ffffff80,0x..fffffff].
+  r0.union_ (r1);
+  // r1 = [128, 0x..ffffff7f].
+  r1 = int_range<1> (UINT128(128),
+		     fold_build2 (MINUS_EXPR, u128_type,
+				  build_minus_one_cst (u128_type),
+				  UINT128(128)));
+  r0.invert ();
+  ASSERT_TRUE (r0 == r1);
+
+  r0.set_varying (integer_type_node);
+  tree minint = wide_int_to_tree (integer_type_node, r0.lower_bound ());
+  tree maxint = wide_int_to_tree (integer_type_node, r0.upper_bound ());
+
+  r0.set_varying (short_integer_type_node);
+
+  r0.set_varying (unsigned_type_node);
+  tree maxuint = wide_int_to_tree (unsigned_type_node, r0.upper_bound ());
+
+  // Check that ~[0,5] => [6,MAX] for unsigned int.
+  r0 = int_range<1> (UINT (0), UINT (5));
+  r0.invert ();
+  ASSERT_TRUE (r0 == int_range<1> (UINT(6), maxuint));
+
+  // Check that ~[10,MAX] => [0,9] for unsigned int.
+  r0 = int_range<1> (UINT(10), maxuint);
+  r0.invert ();
+  ASSERT_TRUE (r0 == int_range<1> (UINT (0), UINT (9)));
+
+  // Check that ~[0,5] => [6,MAX] for unsigned 128-bit numbers.
+  r0 = int_range<1> (UINT128 (0), UINT128 (5), VR_ANTI_RANGE);
+  r1 = int_range<1> (UINT128(6), build_minus_one_cst (u128_type));
+  ASSERT_TRUE (r0 == r1);
+
+  // Check that [~5] is really [-MIN,4][6,MAX].
+  r0 = int_range<1> (INT (5), INT (5), VR_ANTI_RANGE);
+  r1 = int_range<1> (minint, INT (4));
+  r1.union_ (int_range<1> (INT (6), maxint));
+  ASSERT_FALSE (r1.undefined_p ());
+  ASSERT_TRUE (r0 == r1);
+
+  r1 = int_range<1> (INT (5), INT (5));
+  int_range<1> r2 (r1);
+  ASSERT_TRUE (r1 == r2);
+
+  r1 = int_range<1> (INT (5), INT (10));
+
+  r1 = int_range<1> (integer_type_node,
+		     wi::to_wide (INT (5)), wi::to_wide (INT (10)));
+  ASSERT_TRUE (r1.contains_p (INT (7)));
+
+  r1 = int_range<1> (SCHAR (0), SCHAR (20));
+  ASSERT_TRUE (r1.contains_p (SCHAR(15)));
+  ASSERT_FALSE (r1.contains_p (SCHAR(300)));
+
+  // NOT([10,20]) ==> [-MIN,9][21,MAX].
+  r0 = r1 = int_range<1> (INT (10), INT (20));
+  r2 = int_range<1> (minint, INT(9));
+  r2.union_ (int_range<1> (INT(21), maxint));
+  ASSERT_FALSE (r2.undefined_p ());
+  r1.invert ();
+  ASSERT_TRUE (r1 == r2);
+  // Test that NOT(NOT(x)) == x.
+  r2.invert ();
+  ASSERT_TRUE (r0 == r2);
+
+  // Test that booleans and their inverse work as expected.
+  r0 = range_zero (boolean_type_node);
+  ASSERT_TRUE (r0 == int_range<1> (build_zero_cst (boolean_type_node),
+				   build_zero_cst (boolean_type_node)));
+  r0.invert ();
+  ASSERT_TRUE (r0 == int_range<1> (build_one_cst (boolean_type_node),
+				   build_one_cst (boolean_type_node)));
+
+  // Make sure NULL and non-NULL of pointer types work, and that
+  // inverses of them are consistent.
+  tree voidp = build_pointer_type (void_type_node);
+  r0 = range_zero (voidp);
+  r1 = r0;
+  r0.invert ();
+  r0.invert ();
+  ASSERT_TRUE (r0 == r1);
+
+  // [10,20] U [15, 30] => [10, 30].
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (15), INT (30));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == int_range<1> (INT (10), INT (30)));
+
+  // [15,40] U [] => [15,40].
+  r0 = int_range<1> (INT (15), INT (40));
+  r1.set_undefined ();
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == int_range<1> (INT (15), INT (40)));
+
+  // [10,20] U [10,10] => [10,20].
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (10), INT (10));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == int_range<1> (INT (10), INT (20)));
+
+  // [10,20] U [9,9] => [9,20].
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (9), INT (9));
+  r0.union_ (r1);
+  ASSERT_TRUE (r0 == int_range<1> (INT (9), INT (20)));
+
+  // [10,20] ^ [15,30] => [15,20].
+  r0 = int_range<1> (INT (10), INT (20));
+  r1 = int_range<1> (INT (15), INT (30));
+  r0.intersect (r1);
+  ASSERT_TRUE (r0 == int_range<1> (INT (15), INT (20)));
+
+  // Test the internal sanity of wide_int's wrt HWIs.
+  ASSERT_TRUE (wi::max_value (TYPE_PRECISION (boolean_type_node),
+			      TYPE_SIGN (boolean_type_node))
+	       == wi::uhwi (1, TYPE_PRECISION (boolean_type_node)));
+
+  // Test zero_p().
+  r0 = int_range<1> (INT (0), INT (0));
+  ASSERT_TRUE (r0.zero_p ());
+
+  // Test nonzero_p().
+  r0 = int_range<1> (INT (0), INT (0));
+  r0.invert ();
+  ASSERT_TRUE (r0.nonzero_p ());
+
+  // test legacy interaction
+  // r0 = ~[1,1]
+  r0 = int_range<1> (UINT (1), UINT (1), VR_ANTI_RANGE);
+  // r1 = ~[3,3]
+  r1 = int_range<1> (UINT (3), UINT (3), VR_ANTI_RANGE);
+
+  // vv = [0,0][2,2][4, MAX]
+  int_range<3> vv = r0;
+  vv.intersect (r1);
+
+  ASSERT_TRUE (vv.contains_p (UINT (2)));
+  ASSERT_TRUE (vv.num_pairs () == 3);
+
+  // create r0 as legacy [1,1]
+  r0 = int_range<1> (UINT (1), UINT (1));
+  // And union it with  [0,0][2,2][4,MAX] multi range
+  r0.union_ (vv);
+  // The result should be [0,2][4,MAX], or ~[3,3]  but it must contain 2
+  ASSERT_TRUE (r0.contains_p (UINT (2)));
+}
+
+void
+range_tests ()
+{
+  range_tests_legacy ();
+  range_tests_irange3 ();
+  range_tests_int_range_max ();
+  range_tests_misc ();
+}
+
+} // namespace selftest
+
+#endif // CHECKING_P
