aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2020-06-09 07:49:32 +0200
committerAldy Hernandez <aldyh@redhat.com>2020-06-09 07:49:32 +0200
commitdf663310eec78e530cb3360434791352139f496f (patch)
tree38f176522772949def88f2795585677e70d570da
parenta5b9a237d6b83b5956894ce82b70b97cd7620e41 (diff)
downloadgcc-df663310eec78e530cb3360434791352139f496f.zip
gcc-df663310eec78e530cb3360434791352139f496f.tar.gz
gcc-df663310eec78e530cb3360434791352139f496f.tar.bz2
Fix operator_rshift::op1_range to work better with signed types.
We do this by discarding impossible ranges from the incoming LHS.
-rw-r--r--gcc/range-op.cc51
1 files changed, 49 insertions, 2 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 7090467..b3fb57f 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -1602,9 +1602,14 @@ operator_rshift::op1_range (irange &r,
tree shift;
if (op2.singleton_p (&shift))
{
+ // Folding the original operation may discard some impossible
+ // ranges from the LHS.
+ widest_irange lhs_refined;
+ op_rshift.fold_range (lhs_refined, type, value_range (type), op2);
+ lhs_refined.intersect (lhs);
widest_irange shift_range (shift, shift);
widest_irange lb, ub;
- op_lshift.fold_range (lb, type, lhs, shift_range);
+ op_lshift.fold_range (lb, type, lhs_refined, shift_range);
// LHS
// 0000 0111 = OP1 >> 3
//
@@ -1621,7 +1626,7 @@ operator_rshift::op1_range (irange &r,
r = lb;
r.union_ (ub);
- if (!lhs.contains_p (build_zero_cst (lhs.type ())))
+ if (!lhs_refined.contains_p (build_zero_cst (type)))
{
mask_range.invert ();
r.intersect (mask_range);
@@ -3479,6 +3484,48 @@ operator_tests ()
build_int_cst (big_type, 48));
ASSERT_TRUE (res.contains_p (val));
}
+
+ // unsigned: [3, MAX] = OP1 >> 1
+ {
+ widest_irange lhs (build_int_cst (unsigned_type_node, 3),
+ TYPE_MAX_VALUE (unsigned_type_node));
+ widest_irange one (build_one_cst (unsigned_type_node),
+ build_one_cst (unsigned_type_node));
+ widest_irange op1;
+ op_rshift.op1_range (op1, unsigned_type_node, lhs, one);
+ ASSERT_FALSE (op1.contains_p (UINT (3)));
+ }
+
+ // signed: [3, MAX] = OP1 >> 1
+ {
+ widest_irange lhs (INT (3), TYPE_MAX_VALUE (integer_type_node));
+ widest_irange one (INT (1), INT (1));
+ widest_irange 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
+ {
+ widest_irange lhs (TYPE_MIN_VALUE (integer_type_node),
+ TYPE_MIN_VALUE (integer_type_node));
+ widest_irange one (INT (1), INT (1));
+ widest_irange op1;
+ op_rshift.op1_range (op1, integer_type_node, lhs, one);
+ ASSERT_TRUE (op1.undefined_p ());
+ }
+
+ // signed: ~[-1] = OP1 >> 31
+ {
+ widest_irange lhs (INT (-1), INT (-1), VR_ANTI_RANGE);
+ widest_irange shift (INT (31), INT (31));
+ widest_irange op1;
+ op_rshift.op1_range (op1, integer_type_node, lhs, shift);
+ widest_irange negatives = range_negatives (integer_type_node);
+ negatives.intersect (op1);
+ ASSERT_TRUE (negatives.undefined_p ());
+ }
}
// Run all of the selftests within this file.