From: Aldy Hernandez Date: Mon, 9 Nov 2020 13:18:12 +0000 (+0100) Subject: Clean up irange self tests. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b5cff0db6e3a733e470ffc36a3e14c55465bdca2;p=gcc.git Clean up irange self tests. Currently we have all the irange and range-op tests in range-op.cc. This patch splits them up into the appropriate file (irange tests in value-range.cc and range-op tests in range-op.cc). The patch also splits up the tests themselves by functionality. It's not perfect, but significantly better than the mess we had. gcc/ChangeLog: * function-tests.c (test_ranges): Call range_op_tests. * range-op.cc (build_range3): Move to value-range.cc. (range3_tests): Same. (int_range_max_tests): Same. (multi_precision_range_tests): Same. (range_tests): Same. (operator_tests): Split up... (range_op_tests): Split up... (range_op_cast_tests): ...here. (range_op_lshift_tests): ...here. (range_op_rshift_tests): ...here. (range_op_bitwise_and_tests): ...here. * selftest.h (range_op_tests): New. * value-range.cc (build_range3): New. (range_tests_irange3): New. (range_tests_int_range_max): New. (range_tests_legacy): New. (range_tests_misc): New. (range_tests): New. --- 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 2124e229e0c..61f7da278d6 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -2068,3 +2068,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