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 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