From: Andrew MacLeod Date: Wed, 25 Oct 2023 13:46:50 +0000 (-0400) Subject: Adjust operators equal and not_equal to check bitmasks against constants X-Git-Tag: basepoints/gcc-15~5029 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7ab79a40b546a1470abaf76bec74c63e9990fe47;p=thirdparty%2Fgcc.git Adjust operators equal and not_equal to check bitmasks against constants Check to see if a comparison to a constant can be determined to always be not-equal based on the bitmask. PR tree-optimization/111766 gcc/ * range-op.cc (operator_equal::fold_range): Check constants against the bitmask. (operator_not_equal::fold_range): Ditto. * value-range.h (irange_bitmask::member_p): New. gcc/testsuite/ * gcc.dg/pr111766.c: New. --- diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 33b193be7d09..6137f2aeed37 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -931,8 +931,9 @@ operator_equal::fold_range (irange &r, tree type, // We can be sure the values are always equal or not if both ranges // consist of a single value, and then compare them. - if (wi::eq_p (op1.lower_bound (), op1.upper_bound ()) - && wi::eq_p (op2.lower_bound (), op2.upper_bound ())) + bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ()); + bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ()); + if (op1_const && op2_const) { if (wi::eq_p (op1.lower_bound (), op2.upper_bound())) r = range_true (type); @@ -947,6 +948,11 @@ operator_equal::fold_range (irange &r, tree type, tmp.intersect (op2); if (tmp.undefined_p ()) r = range_false (type); + // Check if a constant cannot satisfy the bitmask requirements. + else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ())) + r = range_false (type); + else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ())) + r = range_false (type); else r = range_true_and_false (type); } @@ -1033,8 +1039,9 @@ operator_not_equal::fold_range (irange &r, tree type, // We can be sure the values are always equal or not if both ranges // consist of a single value, and then compare them. - if (wi::eq_p (op1.lower_bound (), op1.upper_bound ()) - && wi::eq_p (op2.lower_bound (), op2.upper_bound ())) + bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ()); + bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ()); + if (op1_const && op2_const) { if (wi::ne_p (op1.lower_bound (), op2.upper_bound())) r = range_true (type); @@ -1049,6 +1056,11 @@ operator_not_equal::fold_range (irange &r, tree type, tmp.intersect (op2); if (tmp.undefined_p ()) r = range_true (type); + // Check if a constant cannot satisfy the bitmask requirements. + else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ())) + r = range_true (type); + else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ())) + r = range_true (type); else r = range_true_and_false (type); } diff --git a/gcc/testsuite/gcc.dg/pr111766.c b/gcc/testsuite/gcc.dg/pr111766.c new file mode 100644 index 000000000000..c27a029c772c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111766.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp" } */ + +int +foo3n(int c, int bb) +{ + if ((bb & ~3)!=0) __builtin_unreachable(); // bb = [0,3] + if ((bb & 1)==0) __builtin_unreachable(); // bb&1 == 0 // [0],[3] + if(bb == 2) __builtin_trap(); + return bb; +} + +/* { dg-final { scan-tree-dump-not "trap" "evrp" } } */ diff --git a/gcc/value-range.h b/gcc/value-range.h index 84f65ffb5910..330e6f70c6b6 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -139,6 +139,7 @@ public: void verify_mask () const; void dump (FILE *) const; + bool member_p (const wide_int &val) const; void adjust_range (irange &r) const; // Convenience functions for nonzero bitmask compatibility. @@ -202,6 +203,19 @@ irange_bitmask::set_nonzero_bits (const wide_int &bits) verify_mask (); } +// Return TRUE if val could be a valid value with this bitmask. + +inline bool +irange_bitmask::member_p (const wide_int &val) const +{ + if (unknown_p ()) + return true; + wide_int res = m_mask & val; + if (m_value != 0) + res |= ~m_mask & m_value; + return res == val; +} + inline bool irange_bitmask::operator== (const irange_bitmask &src) const {