https://gcc.gnu.org/g:8d5eb4f6c1f248340f12adbe76882c3615343e8b

commit r16-6753-g8d5eb4f6c1f248340f12adbe76882c3615343e8b
Author: Pengxuan Zheng <[email protected]>
Date:   Fri Jan 9 10:49:45 2026 -0800

    match: (X >> C) NE/EQ 0 -> X LT/GE 0 [PR123109]
    
    Implement (X >> C) NE/EQ 0 -> X LT/GE 0 in match.pd instead of 
fold-const.cc.
    
    Bootstrapped and tested on x86_64 and aarch64.
    
            PR tree-optimization/123109
    
    gcc/ChangeLog:
    
            * fold-const.cc (fold_binary_loc): Remove (X >> C) NE/EQ 0 -> X 
LT/GE 0
            folding.
            * match.pd (`(X >> C) NE/EQ 0 -> X LT/GE 0`): New pattern.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/vrp99.c: Update test.
            * gcc.dg/pr123109.c: New test.
    
    Signed-off-by: Pengxuan Zheng <[email protected]>

Diff:
---
 gcc/fold-const.cc                     | 34 ----------------------------------
 gcc/match.pd                          | 22 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr123109.c       | 25 +++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp99.c |  2 +-
 4 files changed, 48 insertions(+), 35 deletions(-)

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index f7b712f0c781..47cd0053d31a 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -12392,40 +12392,6 @@ fold_binary_loc (location_t loc, enum tree_code code, 
tree type,
                                      build_int_cst (TREE_TYPE (iref), 0));
            }
        }
-
-      /* Fold (X >> C) != 0 into X < 0 if C is one less than the width
-        of X.  Similarly fold (X >> C) == 0 into X >= 0.  */
-      if (TREE_CODE (arg0) == RSHIFT_EXPR
-         && integer_zerop (arg1)
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       {
-         tree arg00 = TREE_OPERAND (arg0, 0);
-         tree arg01 = TREE_OPERAND (arg0, 1);
-         tree itype = TREE_TYPE (arg00);
-         if (wi::to_wide (arg01) == element_precision (itype) - 1)
-           {
-             if (TYPE_UNSIGNED (itype))
-               {
-                 itype = signed_type_for (itype);
-                 arg00 = fold_convert_loc (loc, itype, arg00);
-               }
-             enum tree_code code2 = code == EQ_EXPR ? GE_EXPR : LT_EXPR;
-             /* Make sure to transform vector compares only to supported
-                ones or from unsupported ones and check that only after
-                IPA so offloaded code is handled correctly in this regard.  */
-             if (!VECTOR_TYPE_P (itype)
-                 || (cfun
-                     && cfun->after_inlining
-                     /* We can jump on EQ/NE but not GE/LT.  */
-                     && VECTOR_BOOLEAN_TYPE_P (type)
-                     && (expand_vec_cmp_expr_p (itype, type, code2)
-                         || !expand_vec_cmp_expr_p (TREE_TYPE (op0),
-                                                    type, code))))
-               return fold_build2_loc (loc, code2,
-                                       type, arg00, build_zero_cst (itype));
-           }
-       }
-
       /* Fold (~X & C) == 0 into (X & C) != 0 and (~X & C) != 0 into
         (X & C) == 0 when C is a single bit.  */
       if (TREE_CODE (arg0) == BIT_AND_EXPR
diff --git a/gcc/match.pd b/gcc/match.pd
index 2be1c5d83f1a..400330aae541 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2832,6 +2832,28 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        (le (minus (convert:etype @0) { lo; }) { hi; })
        (gt (minus (convert:etype @0) { lo; }) { hi; })))))))))
 
+/* Fold (X >> C) != 0 into X < 0 if C is one less than the width
+   of X.  Similarly fold (X >> C) == 0 into X >= 0.  */
+(for neeq (ne eq)
+     ltge (lt ge)
+ (simplify
+  (neeq
+   (rshift@2 @0 INTEGER_CST@1)
+   integer_zerop)
+  (with { tree itype = signed_type_for (TREE_TYPE (@0)); }
+   /* Make sure to transform vector compares only to supported
+      ones or from unsupported ones and check that only after
+      IPA so offloaded code is handled correctly in this regard.  */
+   (if (wi::to_wide (@1) == element_precision (itype) - 1
+       && (!VECTOR_TYPE_P (itype)
+           || (cfun
+               && cfun->after_inlining
+               && VECTOR_BOOLEAN_TYPE_P (type)
+               && (expand_vec_cmp_expr_p (itype, type, ltge)
+                   || !expand_vec_cmp_expr_p (TREE_TYPE (@2),
+                                              type, neeq)))))
+    (ltge (convert:itype @0) { build_zero_cst (itype); })))))
+
 /* X + Z < Y + Z is the same as X < Y when there is no overflow.  */
 (for op (lt le ge gt)
  (simplify
diff --git a/gcc/testsuite/gcc.dg/pr123109.c b/gcc/testsuite/gcc.dg/pr123109.c
new file mode 100644
index 000000000000..9b83d5787138
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr123109.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+typedef int v4si __attribute__((vector_size(4 * sizeof(int))));
+typedef unsigned int v4usi __attribute__((vector_size(4 * sizeof(unsigned 
int))));
+
+#define TEST_NE(type)                                         \
+  type test_ne_##type (type a) { return (a >> 31) != 0; }
+
+#define TEST_EQ(type)                                         \
+  type test_eq_##type (type a) { return (a >> 31) == 0; }
+
+TEST_NE(int)
+TEST_NE(unsigned)
+TEST_NE(v4si)
+TEST_NE(v4usi)
+TEST_EQ(int)
+TEST_EQ(unsigned)
+TEST_EQ(v4si)
+TEST_EQ(v4usi)
+
+/* { dg-final { scan-tree-dump-times ">= 0" 2 optimized } } */
+/* { dg-final { scan-tree-dump-times "< 0" 2 optimized } } */
+/* { dg-final { scan-tree-dump-times ">= { 0, 0, 0, 0 }" 2 optimized } } */
+/* { dg-final { scan-tree-dump-times ">> 31" 2 optimized } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp99.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp99.c
index baa7a706fd98..83c37c3771dc 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp99.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp99.c
@@ -3,7 +3,7 @@
 
 unsigned f(unsigned i){
   i >>= __SIZEOF_INT__ * __CHAR_BIT__ - 1;
-  return i == 0;
+  return i == 1;
 }
 
 /* { dg-final { scan-tree-dump-not "\\(unsigned int\\)" "vrp1" } } */

Reply via email to