https://gcc.gnu.org/g:f36a26b24c524434b11908f0e56ff33dba517f6b
commit r17-1951-gf36a26b24c524434b11908f0e56ff33dba517f6b Author: Naveen <[email protected]> Date: Sun Jun 28 20:36:13 2026 -0700 match.pd: Simplify (signed)A >= 0 & (A & INT_MAX) != 0 to (signed)A > 0 [PR112390] 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. gcc/ChangeLog: PR tree-optimization/112390 * 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: PR tree-optimization/112390 * gcc.dg/pr112390.c: New test. * gcc.dg/pr112390_bitint.c: New test. Signed-off-by: Naveen <[email protected]> Diff: --- gcc/match.pd | 16 ++++++ gcc/testsuite/gcc.dg/pr112390.c | 93 ++++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/pr112390_bitint.c | 20 ++++++++ 3 files changed, 129 insertions(+) diff --git a/gcc/match.pd b/gcc/match.pd index 89d348050a1f..5d589989bd1e 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1730,6 +1730,22 @@ 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) + (maskop (bit_and @0 INTEGER_CST@3) integer_zerop)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && !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 000000000000..e28bfca46397 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr112390.c @@ -0,0 +1,93 @@ +/* PR tree-optimization/112390 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +#include <limits.h> + +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 f32s_bitand(int a) +{ + return (a >= 0) & ((a & INT_MAX) != 0); +} + +int f32s_truthand(int a) +{ + return (a >= 0) && ((a & INT_MAX) != 0); +} + +int f32s_bitior(int a) +{ + return (a < 0) | ((a & INT_MAX) == 0); +} + +int f32s_truthor(int a) +{ + return (a < 0) || ((a & 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 f64s_bitand(long long a) +{ + return (a >= 0) & ((a & LLONG_MAX) != 0); +} + +int f64s_truthand(long long a) +{ + return (a >= 0) && ((a & LLONG_MAX) != 0); +} + +int f64s_bitior(long long a) +{ + return (a < 0) | ((a & LLONG_MAX) == 0); +} + +int f64s_truthor(long long a) +{ + return (a < 0) || ((a & LLONG_MAX) == 0); +} + +/* { 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" 8 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "<= 0" 8 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr112390_bitint.c b/gcc/testsuite/gcc.dg/pr112390_bitint.c new file mode 100644 index 000000000000..764be94b72b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr112390_bitint.c @@ -0,0 +1,20 @@ +/* PR tree-optimization/112390 - _BitInt variants */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +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); +} + +/* { 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" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "<= 0" 1 "optimized" } } */
