As mentioned by Jeff in r15-831-g05daf617ea22e1d818295ed2d037456937e23530, we 
don't handle
`(X | Y) & ~Y` -> `X & ~Y` on the gimple level when there are some different 
signed
(but same precision) types dealing with matching `~Y` with the `Y` part. This
improves both gimple_bitwise_equal_p and gimple_bitwise_inverted_equal_p to
be able to say `(truncate)a` and `(truncate)a` are bitwise_equal and
that `~(truncate)a` and `(truncate)a` are bitwise_invert_equal.

Bootstrapped and tested on x86_64-linux-gnu with no regressions.

        PR tree-optimization/115449

gcc/ChangeLog:

        * gimple-match-head.cc (gimple_maybe_truncate): New declaration.
        (gimple_bitwise_equal_p): Match truncations that differ only
        in types with the same precision.
        (gimple_bitwise_inverted_equal_p): For matching after bit_not_with_nop
        call gimple_bitwise_equal_p.
        * match.pd (maybe_truncate): New match pattern.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/bitops-10.c: New test.

Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
---
 gcc/gimple-match-head.cc                  | 17 +++++-------
 gcc/match.pd                              |  7 +++++
 gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c | 34 +++++++++++++++++++++++
 3 files changed, 48 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c

diff --git a/gcc/gimple-match-head.cc b/gcc/gimple-match-head.cc
index e26fa0860ee..924d3f1e710 100644
--- a/gcc/gimple-match-head.cc
+++ b/gcc/gimple-match-head.cc
@@ -243,6 +243,7 @@ optimize_successive_divisions_p (tree divisor, tree 
inner_div)
   gimple_bitwise_equal_p (expr1, expr2, valueize)
 
 bool gimple_nop_convert (tree, tree *, tree (*) (tree));
+bool gimple_maybe_truncate (tree, tree *, tree (*) (tree));
 
 /* Helper function for bitwise_equal_p macro.  */
 
@@ -271,6 +272,10 @@ gimple_bitwise_equal_p (tree expr1, tree expr2, tree 
(*valueize) (tree))
     }
   if (expr2 != expr4 && operand_equal_p (expr1, expr4, 0))
     return true;
+  if (gimple_maybe_truncate (expr3, &expr3, valueize)
+      && gimple_maybe_truncate (expr4, &expr4, valueize)
+      && operand_equal_p (expr3, expr4, 0))
+    return true;
   return false;
 }
 
@@ -318,21 +323,13 @@ gimple_bitwise_inverted_equal_p (tree expr1, tree expr2, 
bool &wascmp, tree (*va
   /* Try if EXPR1 was defined as ~EXPR2. */
   if (gimple_bit_not_with_nop (expr1, &other, valueize))
     {
-      if (operand_equal_p (other, expr2, 0))
-       return true;
-      tree expr4;
-      if (gimple_nop_convert (expr2, &expr4, valueize)
-         && operand_equal_p (other, expr4, 0))
+      if (gimple_bitwise_equal_p (other, expr2, valueize))
        return true;
     }
   /* Try if EXPR2 was defined as ~EXPR1. */
   if (gimple_bit_not_with_nop (expr2, &other, valueize))
     {
-      if (operand_equal_p (other, expr1, 0))
-       return true;
-      tree expr3;
-      if (gimple_nop_convert (expr1, &expr3, valueize)
-         && operand_equal_p (other, expr3, 0))
+      if (gimple_bitwise_equal_p (other, expr1, valueize))
        return true;
     }
 
diff --git a/gcc/match.pd b/gcc/match.pd
index 5cfe81e80b3..3204cf41538 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -200,6 +200,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (match (maybe_bit_not @0)
  (bit_xor_cst@0 @1 @2))
 
+#if GIMPLE
+(match (maybe_truncate @0)
+ (convert @0)
+ (if (INTEGRAL_TYPE_P (type)
+      && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0)))))
+#endif
+
 /* Transform likes of (char) ABS_EXPR <(int) x> into (char) ABSU_EXPR <x>
    ABSU_EXPR returns unsigned absolute value of the operand and the operand
    of the ABSU_EXPR will have the corresponding signed type.  */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c 
b/gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c
new file mode 100644
index 00000000000..000c5aef237
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/bitops-10.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized-raw" } */
+/* PR tree-optimization/115449 */
+
+void setBit_un(unsigned char *a, int b) {
+   unsigned char c = 0x1UL << b;
+   *a &= ~c;
+   *a |= c;
+}
+
+void setBit_sign(signed char *a, int b) {
+   signed char c = 0x1UL << b;
+   *a &= ~c;
+   *a |= c;
+}
+
+void setBit(char *a, int b) {
+   char c = 0x1UL << b;
+   *a &= ~c;
+   *a |= c;
+}
+/*
+   All three should produce:
+    _1 = 1 << b_4(D);
+    c_5 = (cast) _1;
+    _2 = *a_7(D);
+    _3 = _2 | c_5;
+    *a_7(D) = _3;
+   Removing the `&~c` as we are matching `(~x & y) | x` -> `x | y`
+   match pattern even with extra casts are being involved. */
+
+/* { dg-final { scan-tree-dump-not "bit_not_expr, " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "bit_and_expr, " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "bit_ior_expr, " 3 "optimized" } } */
-- 
2.43.0

Reply via email to