MATCH: remove negate for 1bit types
Checks
Commit Message
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
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
>
@@ -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)
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */