MATCH: remove negate for 1bit types

Message ID 20230824023815.3506414-1-apinski@marvell.com
State Accepted
Headers
Series MATCH: remove negate for 1bit types |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Andrew Pinski Aug. 24, 2023, 2:38 a.m. UTC
  For 1bit types, negate is either undefined or don't change the value.
In either cases we want to remove them.
This patch adds a match pattern to do that.
Also converting to a 1bit type we can remove the negate just like we already do
for `&1` so this patch adds that too.

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

Notes on the testcases:
This patch is the last part to fix PR 95929; cond-bool-2.c testcase.
bit1neg-1.c is a 1bit-field testcase where we could remove the assignment
all the way in one case (which happened on the RTL level for some targets but not all).
cond-bool-2.c is the reduced testcase of PR 95929.

	PR tree-optimization/95929

gcc/ChangeLog:

	* match.pd (convert?(-a)): New pattern
	for 1bit integer types.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/bit1neg-1.c: New test.
	* gcc.dg/tree-ssa/cond-bool-1.c: New test.
	* gcc.dg/tree-ssa/cond-bool-2.c: New test.
---
 gcc/match.pd                                | 12 ++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c   | 23 ++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c | 21 +++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c | 26 +++++++++++++++++++++
 4 files changed, 82 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c
  

Comments

Richard Biener Aug. 24, 2023, 6:40 a.m. UTC | #1
On Thu, Aug 24, 2023 at 4:39 AM Andrew Pinski via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> For 1bit types, negate is either undefined or don't change the value.
> In either cases we want to remove them.
> This patch adds a match pattern to do that.
> Also converting to a 1bit type we can remove the negate just like we already do
> for `&1` so this patch adds that too.
>
> OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions.

OK.

Thanks,
Richard.

> Notes on the testcases:
> This patch is the last part to fix PR 95929; cond-bool-2.c testcase.
> bit1neg-1.c is a 1bit-field testcase where we could remove the assignment
> all the way in one case (which happened on the RTL level for some targets but not all).
> cond-bool-2.c is the reduced testcase of PR 95929.
>
>         PR tree-optimization/95929
>
> gcc/ChangeLog:
>
>         * match.pd (convert?(-a)): New pattern
>         for 1bit integer types.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/tree-ssa/bit1neg-1.c: New test.
>         * gcc.dg/tree-ssa/cond-bool-1.c: New test.
>         * gcc.dg/tree-ssa/cond-bool-2.c: New test.
> ---
>  gcc/match.pd                                | 12 ++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c   | 23 ++++++++++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c | 21 +++++++++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c | 26 +++++++++++++++++++++
>  4 files changed, 82 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index a2e56d5a4e8..3bbeceb37b4 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -9090,6 +9090,18 @@ and,
>   (if (!TYPE_OVERFLOW_SANITIZED (type))
>    (bit_and @0 @1)))
>
> +/* `-a` is just `a` if the type is 1bit wide or when converting
> +   to a 1bit type; similar to the above transformation of `(-x)&1`.
> +   This is used mostly with the transformation of
> +   `a ? ~b : b` into `(-a)^b`.
> +   It also can show up with bitfields.  */
> +(simplify
> + (convert? (negate @0))
> + (if (INTEGRAL_TYPE_P (type)
> +      && TYPE_PRECISION (type) == 1
> +      && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)))
> +  (convert @0)))
> +
>  /* Optimize
>     c1 = VEC_PERM_EXPR (a, a, mask)
>     c2 = VEC_PERM_EXPR (b, b, mask)
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c b/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c
> new file mode 100644
> index 00000000000..2f123fbb9b5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +
> +struct f
> +{
> +  int a:1;
> +};
> +
> +void g(struct f *a)
> +{
> + int t = a->a;
> + t = -t;
> + a->a = t;
> +}
> +void g1(struct f *a, int b)
> +{
> + int t = b;
> + t = -t;
> + a->a = t;
> +}
> +/* the 2 negates should have been removed as this is basically the same
> +   as (-a) & 1. */
> +/* { dg-final { scan-tree-dump-not " = -" "optimized" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c
> new file mode 100644
> index 00000000000..752a3030ad1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c
> @@ -0,0 +1,21 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
> +_Bool f1(int a, int b)
> +{
> +  _Bool _1 = b != 0;
> +  _Bool _2 = a != 0;
> +  _Bool _8 = a == 0;
> +  _Bool _13;
> +  if (_1) _13 = _8; else _13 = _2;
> +  return _13;
> +}
> +
> +/* We should be able to optimize this to (a != 0) ^ (b != 0) */
> +/* There should be no negate_expr nor gimple_cond here. */
> +
> +/* { dg-final { scan-tree-dump-not "negate_expr, " "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "ne_expr, " 2 "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "gimple_assign " 3 "optimized" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c
> new file mode 100644
> index 00000000000..b3e7e25dec6
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c
> @@ -0,0 +1,26 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
> +
> +/* PR tree-optimization/95929 */
> +
> +
> +static inline _Bool nand(_Bool a, _Bool b)
> +{
> +    return !(a && b);
> +}
> +
> +_Bool f(int a, int b)
> +{
> +    return nand(nand(b, nand(a, a)), nand(a, nand(b, b)));
> +}
> +
> +/* We should be able to optimize this to (a != 0) ^ (b != 0) */
> +/* There should be no negate_expr nor gimple_cond here. */
> +
> +/* { dg-final { scan-tree-dump-not "negate_expr, " "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "ne_expr, " 2 "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "cond_expr, " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */
> +/* { dg-final { scan-tree-dump-times "gimple_assign " 3 "optimized" } } */
> --
> 2.31.1
>
  

Patch

diff --git a/gcc/match.pd b/gcc/match.pd
index a2e56d5a4e8..3bbeceb37b4 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -9090,6 +9090,18 @@  and,
  (if (!TYPE_OVERFLOW_SANITIZED (type))
   (bit_and @0 @1)))
 
+/* `-a` is just `a` if the type is 1bit wide or when converting
+   to a 1bit type; similar to the above transformation of `(-x)&1`.
+   This is used mostly with the transformation of
+   `a ? ~b : b` into `(-a)^b`.
+   It also can show up with bitfields.  */
+(simplify
+ (convert? (negate @0))
+ (if (INTEGRAL_TYPE_P (type)
+      && TYPE_PRECISION (type) == 1
+      && !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)))
+  (convert @0)))
+
 /* Optimize
    c1 = VEC_PERM_EXPR (a, a, mask)
    c2 = VEC_PERM_EXPR (b, b, mask)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c b/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c
new file mode 100644
index 00000000000..2f123fbb9b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/bit1neg-1.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+struct f
+{
+  int a:1;
+};
+
+void g(struct f *a)
+{
+ int t = a->a;
+ t = -t;
+ a->a = t;
+}
+void g1(struct f *a, int b)
+{
+ int t = b;
+ t = -t;
+ a->a = t;
+}
+/* the 2 negates should have been removed as this is basically the same
+   as (-a) & 1. */
+/* { dg-final { scan-tree-dump-not " = -" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c
new file mode 100644
index 00000000000..752a3030ad1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-1.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+_Bool f1(int a, int b)
+{
+  _Bool _1 = b != 0;
+  _Bool _2 = a != 0;
+  _Bool _8 = a == 0;
+  _Bool _13;
+  if (_1) _13 = _8; else _13 = _2;
+  return _13;
+}
+
+/* We should be able to optimize this to (a != 0) ^ (b != 0) */
+/* There should be no negate_expr nor gimple_cond here. */
+
+/* { dg-final { scan-tree-dump-not "negate_expr, " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "ne_expr, " 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "gimple_assign " 3 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c
new file mode 100644
index 00000000000..b3e7e25dec6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cond-bool-2.c
@@ -0,0 +1,26 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+/* PR tree-optimization/95929 */
+
+
+static inline _Bool nand(_Bool a, _Bool b)
+{
+    return !(a && b);
+}
+
+_Bool f(int a, int b)
+{
+    return nand(nand(b, nand(a, a)), nand(a, nand(b, b)));
+}
+
+/* We should be able to optimize this to (a != 0) ^ (b != 0) */
+/* There should be no negate_expr nor gimple_cond here. */
+
+/* { dg-final { scan-tree-dump-not "negate_expr, " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "ne_expr, " 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-not "gimple_cond " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "cond_expr, " "optimized" } } */
+/* { dg-final { scan-tree-dump-not "gimple_phi " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "bit_xor_expr, " 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "gimple_assign " 3 "optimized" } } */