match.pd: Generalize the PR64309 simplifications [PR96669]
authorJakub Jelinek <jakub@redhat.com>
Fri, 15 Jan 2021 20:12:14 +0000 (21:12 +0100)
committerJakub Jelinek <jakub@redhat.com>
Fri, 15 Jan 2021 20:12:14 +0000 (21:12 +0100)
The following patch generalizes the PR64309 simplifications, so that instead
of working only with constants 1 and 1 it works with any two power of two
constants, and works also for right shift (in that case it rules out the
first one being negative, as it is arithmetic shift then).

2021-01-15  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/96669
* match.pd (((1 << A) & 1) != 0 -> A == 0,
((1 << A) & 1) == 0 -> A != 0): Generalize for 1s replaced by
possibly different power of two constants and to right shift too.

* gcc.dg/tree-ssa/pr96669-1.c: New test.

gcc/match.pd
gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c [new file with mode: 0644]

index e731bdba171e82dfdba3938ea51db5024b225a76..84c4ee66a79fe026ff1351e7b12af0e40ee25777 100644 (file)
@@ -3117,13 +3117,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       (op @0 { build_int_cst (TREE_TYPE (@1), low); })))))))
 
 
-/* ((1 << A) & 1) != 0 -> A == 0
-   ((1 << A) & 1) == 0 -> A != 0 */
+/* Simplify ((C << x) & D) != 0 where C and D are power of two constants,
+   either to false if D is smaller (unsigned comparison) than C, or to
+   x == log2 (D) - log2 (C).  Similarly for right shifts.  */
 (for cmp (ne eq)
      icmp (eq ne)
  (simplify
-  (cmp (bit_and (lshift integer_onep @0) integer_onep) integer_zerop)
-  (icmp @0 { build_zero_cst (TREE_TYPE (@0)); })))
+  (cmp (bit_and (lshift integer_pow2p@1 @0) integer_pow2p@2) integer_zerop)
+   (with { int c1 = wi::clz (wi::to_wide (@1));
+          int c2 = wi::clz (wi::to_wide (@2)); }
+    (if (c1 < c2)
+     { constant_boolean_node (cmp == NE_EXPR ? false : true, type); }
+     (icmp @0 { build_int_cst (TREE_TYPE (@0), c1 - c2); }))))
+ (simplify
+  (cmp (bit_and (rshift integer_pow2p@1 @0) integer_pow2p@2) integer_zerop)
+   (if (tree_int_cst_sgn (@1) > 0)
+    (with { int c1 = wi::clz (wi::to_wide (@1));
+           int c2 = wi::clz (wi::to_wide (@2)); }
+     (if (c1 > c2)
+      { constant_boolean_node (cmp == NE_EXPR ? false : true, type); }
+      (icmp @0 { build_int_cst (TREE_TYPE (@0), c2 - c1); }))))))
 
 /* (CST1 << A) == CST2 -> A == ctz (CST2) - ctz (CST1)
    (CST1 << A) != CST2 -> A != ctz (CST2) - ctz (CST1)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96669-1.c
new file mode 100644 (file)
index 0000000..a1efba7
--- /dev/null
@@ -0,0 +1,59 @@
+/* PR tree-optimization/96669 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-original" } */
+/* { dg-final { scan-tree-dump "return a == 0;" "original" } } */
+/* { dg-final { scan-tree-dump "return 1;" "original" } } */
+/* { dg-final { scan-tree-dump "return c == 3;" "original" } } */
+/* { dg-final { scan-tree-dump "return d != 1;" "original" } } */
+/* { dg-final { scan-tree-dump "return e != 0;" "original" } } */
+/* { dg-final { scan-tree-dump "return f == 1;" "original" } } */
+/* { dg-final { scan-tree-dump "return 0;" "original" } } */
+/* { dg-final { scan-tree-dump "return h != 1;" "original" } } */
+
+int
+f1 (int a)
+{
+  return ((1 << a) & 1) != 0;
+}
+
+int
+f2 (int b)
+{
+  return ((2 << b) & 1) == 0;
+}
+
+int
+f3 (int c)
+{
+  return ((2 << c) & 16) != 0;
+}
+
+int
+f4 (int d)
+{
+  return ((16 << d) & 32) == 0;
+}
+
+int
+f5 (int e)
+{
+  return ((1 >> e) & 1) == 0;
+}
+
+int
+f6 (int f)
+{
+  return ((2 >> f) & 1) != 0;
+}
+
+int
+f7 (int g)
+{
+  return ((1 >> g) & 2) != 0;
+}
+
+int
+f8 (int h)
+{
+  return ((32 >> h) & 16) == 0;
+}