diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2020-06-09 07:49:32 +0200 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2020-06-09 07:49:32 +0200 |
commit | df663310eec78e530cb3360434791352139f496f (patch) | |
tree | 38f176522772949def88f2795585677e70d570da /gcc | |
parent | a5b9a237d6b83b5956894ce82b70b97cd7620e41 (diff) | |
download | gcc-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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/range-op.cc | 51 |
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. |