diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2020-10-26 17:50:37 +0100 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2020-10-26 19:05:53 +0100 |
commit | 2118438f49f0c193abe3fa3def350a8129045746 (patch) | |
tree | 9a14a7334ad2760d8c7ccbdb4de9220544e1c068 /gcc/value-range.cc | |
parent | f20a6c57f0f26d9c60d6d6182f1e2181f727c834 (diff) | |
download | gcc-2118438f49f0c193abe3fa3def350a8129045746.zip gcc-2118438f49f0c193abe3fa3def350a8129045746.tar.gz gcc-2118438f49f0c193abe3fa3def350a8129045746.tar.bz2 |
Handle signed 1-bit ranges in irange::invert.
The problem here is we are trying to add 1 to a -1 in a signed 1-bit
field and coming up with UNDEFINED because of the overflow.
Signed 1-bits are annoying because you can't really add or subtract
one, because the one is unrepresentable. For invert() we have a
special subtract_one() function that handles 1-bit signed fields.
This patch implements the analogous add_one() function so that invert
works.
gcc/ChangeLog:
PR tree-optimization/97555
* range-op.cc (range_tests): Test 1-bit signed invert.
* value-range.cc (subtract_one): Adjust comment.
(add_one): New.
(irange::invert): Call add_one.
gcc/testsuite/ChangeLog:
* gcc.dg/pr97555.c: New test.
Diffstat (limited to 'gcc/value-range.cc')
-rw-r--r-- | gcc/value-range.cc | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 7847104..0e633c1 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -1772,19 +1772,30 @@ irange::irange_intersect (const irange &r) verify_range (); } +// Signed 1-bits are strange. You can't subtract 1, because you can't +// represent the number 1. This works around that for the invert routine. + static wide_int inline subtract_one (const wide_int &x, tree type, wi::overflow_type &overflow) { - // A signed 1-bit bit-field, has a range of [-1,0] so subtracting +1 - // overflows, since +1 is unrepresentable. This is why we have an - // addition of -1 here. if (TYPE_SIGN (type) == SIGNED) - return wi::add (x, -1 , SIGNED, &overflow); + return wi::add (x, -1, SIGNED, &overflow); else return wi::sub (x, 1, UNSIGNED, &overflow); } -/* Return the inverse of a range. */ +// The analogous function for adding 1. + +static wide_int inline +add_one (const wide_int &x, tree type, wi::overflow_type &overflow) +{ + if (TYPE_SIGN (type) == SIGNED) + return wi::sub (x, -1, SIGNED, &overflow); + else + return wi::add (x, 1, UNSIGNED, &overflow); +} + +// Return the inverse of a range. void irange::invert () @@ -1881,7 +1892,7 @@ irange::invert () // set the overflow bit. if (type_max != wi::to_wide (orig_range.m_base[i])) { - tmp = wi::add (wi::to_wide (orig_range.m_base[i]), 1, sign, &ovf); + tmp = add_one (wi::to_wide (orig_range.m_base[i]), ttype, ovf); m_base[nitems++] = wide_int_to_tree (ttype, tmp); m_base[nitems++] = wide_int_to_tree (ttype, type_max); if (ovf) |