On Mon, Jun 8, 2026 at 4:33 AM Naveen <[email protected]> wrote: > > The patch adds simplifications for the pattern where a sign-bit check and a > lower-bits check are combined with a bitwise or logical AND/OR: > > (1) ((signed)A >= 0) &/&& ((A & INT_MAX) != 0) --> (signed)A > 0 > (2) ((signed)A < 0) |/|| ((A & INT_MAX) == 0) --> (signed)A <= 0 > > Both patterns arise naturally from code that separately tests the sign > bit and the magnitude of an unsigned integer. The combined expression > is equivalent to a single signed comparison, and the simplification > eliminates the intermediate BIT_AND_EXPR mask as well as the weaker > comparison operator. > > Bootstrapped and tested on aarch64-linux-gnu. > > PR tree-optimization/112390 > > gcc/ChangeLog: > * match.pd: Add simplifications for combined sign-bit and > magnitude checks: > ((signed)A >= 0) &/&& ((A & INT_MAX) != 0) -> (signed)A > 0 > ((signed)A < 0) |/|| ((A & INT_MAX) == 0) -> (signed)A <= 0 > > gcc/testsuite/ChangeLog: > * gcc.dg/pr112390.c: New test.
A few comments below. It is close though. > > Signed-off-by: Naveen <[email protected]> > --- > gcc/match.pd | 17 +++++++++ > gcc/testsuite/gcc.dg/pr112390.c | 65 +++++++++++++++++++++++++++++++++ > 2 files changed, 82 insertions(+) > create mode 100644 gcc/testsuite/gcc.dg/pr112390.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index e0d7ef80e14..d68c206e757 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -1712,6 +1712,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (convert (bit_and (negate (convert:utype { pmop[0]; })) > (convert:utype @1))))))) > > +/* (signed)A >= 0 && (A & INT_MAX) != 0 --> (signed)A > 0 > + (signed)A < 0 || (A & INT_MAX) == 0 --> (signed)A <= 0 */ > +(for op (bit_and truth_and bit_ior truth_or) > + signop (ge ge lt lt) > + maskop (ne ne eq eq) > + resop (gt gt le le) > + (simplify > + (op:c > + (signop (nop_convert@2 @0) integer_zerop) (signop (nop_convert?@2 @0) integer_zerop) > + (maskop (bit_and @0 INTEGER_CST@3) integer_zerop)) > + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) Remove: > + && TYPE_UNSIGNED (TREE_TYPE (@0)) And just keep: > + && !TYPE_UNSIGNED (TREE_TYPE (@2)) > + && wi::eq_p (wi::to_wide (@3), > + wi::max_value (TYPE_PRECISION (TREE_TYPE (@0)), SIGNED))) > + (resop @2 { build_zero_cst (TREE_TYPE (@2)); })))) > + > /* X % Y is smaller than Y. */ > (for cmp (lt ge) > (simplify > diff --git a/gcc/testsuite/gcc.dg/pr112390.c b/gcc/testsuite/gcc.dg/pr112390.c > new file mode 100644 > index 00000000000..e2043c8de5f > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr112390.c > @@ -0,0 +1,65 @@ > +/* PR tree-optimization/112390 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized" } */ > + > +#include <limits.h> > + Duplicate the testcase and use `signed int` too. > +int f32_bitand(unsigned int a) > +{ > + return ((int)a >= 0) & ((a & (unsigned)INT_MAX) != 0); > +} > + > +int f32_truthand(unsigned int a) > +{ > + return ((int)a >= 0) && ((a & (unsigned)INT_MAX) != 0); > +} > + > +int f32_bitior(unsigned int a) > +{ > + return ((int)a < 0) | ((a & (unsigned)INT_MAX) == 0); > +} > + > +int f32_truthor(unsigned int a) > +{ > + return ((int)a < 0) || ((a & (unsigned)INT_MAX) == 0); > +} > + > +int f64_bitand(unsigned long long a) > +{ > + return ((long long)a >= 0) & ((a & (unsigned long long)LLONG_MAX) != 0); > +} > + > +int f64_truthand(unsigned long long a) > +{ > + return ((long long)a >= 0) && ((a & (unsigned long long)LLONG_MAX) != 0); > +} > + > +int f64_bitior(unsigned long long a) > +{ > + return ((long long)a < 0) | ((a & (unsigned long long)LLONG_MAX) == 0); > +} > + > +int f64_truthor(unsigned long long a) > +{ > + return ((long long)a < 0) || ((a & (unsigned long long)LLONG_MAX) == 0); > +} > + > +int fbit11_ior(unsigned _BitInt(11) a) > +{ > + signed _BitInt(11) sa = (signed _BitInt(11))a; > + return (sa < 0) | ((a & 1023wb) == 0); > +} > + > +int fbit11_and(unsigned _BitInt(11) a) > +{ > + signed _BitInt(11) sa = (signed _BitInt(11))a; > + return (sa >= 0) & ((a & 1023wb) != 0); > +} These should be into their own testcase and need `target bitint` on the dg-do part. Thanks, Andrea > + > +/* { dg-final { scan-tree-dump-times ">= 0" 0 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "< 0" 0 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "BIT_AND_EXPR" 0 "optimized" } } */ > +/* { dg-final { scan-tree-dump-not "bit_and" "optimized" } } */ > +/* { dg-final { scan-tree-dump-not "bit_ior" "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "> 0" 5 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "<= 0" 5 "optimized" } } */ > -- > 2.34.1 >
