https://gcc.gnu.org/g:9560cd83671a32ee2253f307112ac39b40aa712c
commit r16-1562-g9560cd83671a32ee2253f307112ac39b40aa712c Author: Andrew MacLeod <amacl...@redhat.com> Date: Wed May 28 16:27:16 2025 -0400 Improve contains_p and intersect with bitmasks. Improve the way contains_p (wide_int) and intersect behave wioth singletons and bitmasks. Also fix a buglet in bitmask_intersect when the result is a singleton which is not in the current range. PR tree-optimization/119039 gcc/ * value-range.cc (irange::contains_p): Call wide_int version of contains_p for singleton ranges. (irange::intersect): If either range is a singleton, use contains_p. gcc/testsuite/ * gcc.dg/pr119039-2.c: New. Diff: --- gcc/testsuite/gcc.dg/pr119039-2.c | 60 +++++++++++++++++++++++++++++++++++++++ gcc/value-range.cc | 23 +++++++++++---- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/gcc/testsuite/gcc.dg/pr119039-2.c b/gcc/testsuite/gcc.dg/pr119039-2.c new file mode 100644 index 000000000000..634b40028209 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr119039-2.c @@ -0,0 +1,60 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +extern void good (void); +extern void bad (void); + +/* Switch simplification should remove 'case 2:' because 'i' will always + * have its 0th bit set (odd). */ + +void bitmask_elimination_1(int i) +{ + i = i | 1; + + switch (i) + { + case 1: + good (); + break; + + // This case should be removed; + case 2: + bad (); + break; + + case 3: + good (); + break; + + default: + break; + } +} + +/* Switch simplification should remove 'case 20-28:' because 'i' will always + * be a multiple of 16. */ +void bitmask_elimination_2 (int i) +{ + int masked_val = i & 0xF0; // This zeroes out the lower 4 bits of 'i' + + switch (masked_val) + { + case 0: + good (); // Reachable. + break; + + // This entire cased should be removed; + case 20 ... 28: + bad (); + break; + + case 32: + good (); // Reachable. + break; + + default: + good (); + break; + } +} +/* { dg-final { scan-tree-dump-not "bad" "evrp" } } */ diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 5e97fdb76919..348c68ec902e 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -1628,10 +1628,8 @@ irange::contains_p (const wide_int &cst) const if (undefined_p ()) return false; - // See if we can exclude CST based on the known 0 bits. - if (!m_bitmask.unknown_p () - && cst != 0 - && wi::bit_and (m_bitmask.get_nonzero_bits (), cst) == 0) + // Check is the known bits in bitmask exclude CST. + if (!m_bitmask.member_p (cst)) return false; signop sign = TYPE_SIGN (type ()); @@ -1899,12 +1897,17 @@ irange::irange_contains_p (const irange &r) const gcc_checking_assert (!undefined_p () && !varying_p ()); gcc_checking_assert (!r.undefined_p () && !varying_p ()); + // Check singletons directly which will include any bitmasks. + wide_int rl; + if (r.singleton_p (rl)) + return contains_p (rl); + // In order for THIS to fully contain R, all of the pairs within R must // be fully contained by the pairs in this object. signop sign = TYPE_SIGN (m_type); unsigned ri = 0; unsigned i = 0; - wide_int rl = r.m_base[0]; + rl = r.m_base[0]; wide_int ru = r.m_base[1]; wide_int l = m_base[0]; wide_int u = m_base[1]; @@ -1973,6 +1976,16 @@ irange::intersect (const vrange &v) return res; } + // If either range is a singleton and the other range does not contain + // it, the result is undefined. + wide_int val; + if ((singleton_p (val) && !r.contains_p (val)) + || (r.singleton_p (val) && !contains_p (val))) + { + set_undefined (); + return true; + } + // If R fully contains this, then intersection will change nothing. if (r.irange_contains_p (*this)) return intersect_bitmask (r);