From: Dhruv Chawla <dhr...@nvidia.com>

For ==, < and <=, the fold is to 0. For !=, > and >=, the fold is to 1.
This only applies when C != 0.

Bootstrapped and regtested on aarch64-linux-gnu.

Signed-off-by: Dhruv Chawla <dhr...@nvidia.com>

gcc/ChangeLog:

        * match.pd: New patterns.

gcc/testsuite/ChangeLog:

        * gcc.dg/match-constant-shift-1.c: New test.
        * gcc.dg/match-constant-shift-1.c: Likewise.
---
 gcc/match.pd                                  | 18 ++++++
 gcc/testsuite/gcc.dg/match-constant-shift-1.c | 46 +++++++++++++++
 gcc/testsuite/gcc.dg/match-constant-shift-2.c | 59 +++++++++++++++++++
 3 files changed, 123 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/match-constant-shift-1.c
 create mode 100644 gcc/testsuite/gcc.dg/match-constant-shift-2.c

diff --git a/gcc/match.pd b/gcc/match.pd
index b1d7a3a1b73..4e8fbaa4dd9 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1316,6 +1316,24 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (INTEGRAL_TYPE_P (type))
       (rshift (op @0 @2) @1))))
 
+#if GIMPLE
+/* (y << x) {==,<,<=} x -> 0 when y != 0.  */
+(for cmp (eq lt le)
+  (simplify
+    (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
+    (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+        && tree_expr_nonzero_p (@0))
+     { build_zero_cst (type); })))
+
+/* (y << x) {!=,>,>=} x -> 1 when y != 0.  */
+(for cmp (ne gt ge)
+  (simplify
+    (cmp:c (nop_convert1? (lshift @0 @1)) (nop_convert2? @1))
+    (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+        && tree_expr_nonzero_p (@0))
+     { build_one_cst (type); })))
+#endif
+
 /* Fold (1 << (C - x)) where C = precision(type) - 1
    into ((1 << C) >> x). */
 (simplify
diff --git a/gcc/testsuite/gcc.dg/match-constant-shift-1.c 
b/gcc/testsuite/gcc.dg/match-constant-shift-1.c
new file mode 100644
index 00000000000..8e7a620e951
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/match-constant-shift-1.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-optimized" } */
+
+#define TEST_ONE_CST(n, op, type, cst)                                         
\
+  bool lshift_cst_##type##n (type x) { return (cst << x) op x; }
+
+#define TEST_OP_CST(n, op)                                                     
\
+  TEST_ONE_CST (n, op, unsigned, n)                                            
\
+  TEST_ONE_CST (n, op, int, n)                                                 
\
+  TEST_ONE_CST (n, op, bool, n)                                                
\
+  TEST_ONE_CST (n, op, test_enum, n)
+
+#define TEST_ONE(n, op, type)                                                  
\
+  bool lshift_##type##n (type x, type y)                                       
\
+  {                                                                            
\
+    if (y <= 0)                                                                
\
+      __builtin_unreachable ();                                                
\
+    return (y << x) op x;                                                      
\
+  }
+
+#define TEST_OP(n, op)                                                         
\
+  TEST_ONE (n, op, unsigned)                                                   
\
+  TEST_ONE (n, op, int)                                                        
\
+  TEST_ONE (n, op, bool)                                                       
\
+  TEST_ONE (n, op, test_enum)
+
+typedef enum
+{
+  ZERO
+} test_enum;
+
+TEST_OP_CST (1, ==)
+TEST_OP_CST (2, !=)
+TEST_OP_CST (3, <)
+TEST_OP_CST (4, >)
+TEST_OP_CST (5, <=)
+TEST_OP_CST (6, >=)
+
+TEST_OP (1, ==)
+TEST_OP (2, !=)
+TEST_OP (3, <)
+TEST_OP (4, >)
+TEST_OP (5, <=)
+TEST_OP (6, >=)
+
+/* { dg-final { scan-tree-dump-not "<<" optimized } } */
diff --git a/gcc/testsuite/gcc.dg/match-constant-shift-2.c 
b/gcc/testsuite/gcc.dg/match-constant-shift-2.c
new file mode 100644
index 00000000000..d6a4a3012f2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/match-constant-shift-2.c
@@ -0,0 +1,59 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* The fold (C << x) <op> x -> 0|1 shouldn't trigger when C is 0.  */
+
+#define TEST_ONE_CST(n, op, type, cst)                                         
\
+  type lshift_cst_##type##n (type x) { return (type) ((cst << x) op x); }
+
+#define TEST_OP_CST(n, op, cst)                                                
\
+  TEST_ONE_CST (n, op, unsigned, cst)                                          
\
+  TEST_ONE_CST (n, op, int, cst)                                               
\
+  TEST_ONE_CST (n, op, bool, cst)                                              
\
+  TEST_ONE_CST (n, op, test_enum, cst)
+
+#define TEST_ONE(n, op, type)                                                  
\
+  type lshift_##type##n (type x, type y)                                    \
+  {                                                                            
\
+    if (y != 0)                                                                
\
+      __builtin_unreachable ();                                                
\
+    return (type) ((y << x) op x);                                             
\
+  }
+
+#define TEST_OP(n, op)                                                         
\
+  TEST_ONE (n, op, unsigned)                                                   
\
+  TEST_ONE (n, op, int)                                                        
\
+  TEST_ONE (n, op, bool)                                                       
\
+  TEST_ONE (n, op, test_enum)
+
+typedef enum
+{
+  ZERO
+} test_enum;
+
+TEST_OP_CST (1, ==, 0)
+TEST_OP_CST (2, !=, 0)
+TEST_OP_CST (3, <, 0)
+TEST_OP_CST (4, >, 0)
+TEST_OP_CST (5, <=, 0)
+TEST_OP_CST (6, >=, 0)
+
+TEST_OP (1, ==)
+TEST_OP (2, !=)
+TEST_OP (3, <)
+TEST_OP (4, >)
+TEST_OP (5, <=)
+TEST_OP (6, >=)
+
+/* These end up getting folded by other patterns.  */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) == 0" 10 optimized} } */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) != 0" 10 optimized } } */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) > 0" 2 optimized } } */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) < 0" 2 optimized} } */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) >= 0" 2 optimized } } */
+/* { dg-final { scan-tree-dump-times "x_\\d\\(D\\) <= 0" 2 optimized} } */
+/* { dg-final { scan-tree-dump-times "~x_\\d\\(D\\)" 4 optimized } } */
+/* { dg-final { scan-tree-dump-times "return x_\\d\\(D\\);" 4 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 0;" 6 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 1;" 6 optimized } } */
+/* Total: 48.  */
-- 
2.44.0

Reply via email to