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.
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]>
---
gcc/match.pd | 16 +++++
gcc/testsuite/gcc.dg/pr112390.c | 93 ++++++++++++++++++++++++++
gcc/testsuite/gcc.dg/pr112390_bitint.c | 20 ++++++
3 files changed, 129 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/pr112390.c
create mode 100644 gcc/testsuite/gcc.dg/pr112390_bitint.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 475939a0b63..ea3b270b3ff 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 00000000000..e28bfca4639
--- /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 00000000000..764be94b72b
--- /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" } } */
--
2.34.1