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.

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)
+   (maskop (bit_and @0 INTEGER_CST@3) integer_zerop))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && TYPE_UNSIGNED (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..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>
+
+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);
+}
+
+/* { 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

Reply via email to