From 0bd675183d94e6bca100c3aaaf87ee9676fb3c26 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 12 Dec 2020 14:49:57 +0100 Subject: [PATCH] match.pd: Add ~(X - Y) -> ~X + Y simplification [PR96685] This patch adds the ~(X - Y) -> ~X + Y simplification requested in the PR (plus also ~(X + C) -> ~X + (-C) for constants C that can be safely negated. The first two simplify blocks is what has been requested in the PR and that makes the first testcase pass. Unfortunately, that change also breaks the second testcase, because while the same expressions appearing in the same stmt and split across multiple stmts has been folded (not really) before, with this optimization fold-const.c optimizes ~X + Y further into (Y - X) - 1 in fold_binary_loc associate: code, but we have nothing like that in GIMPLE and so end up with different expressions. The last simplify is an attempt to deal with just this case, had to rule out there the Y == -1U case, because then we reached infinite recursion as ~X + -1U was canonicalized by the pattern into (-1U - X) + -1U but there is a canonicalization -1 - A -> ~A that turns it back. Furthermore, had to make it #if GIMPLE only, because it otherwise resulted in infinite recursion when interacting with the associate: optimization. The end result is that we pass all 3 testcases and thus canonizalize the 3 possible forms of writing the same thing. 2020-12-12 Jakub Jelinek PR tree-optimization/96685 * match.pd (~(X - Y) -> ~X + Y): New optimization. (~X + Y -> (Y - X) - 1): Likewise. * gcc.dg/tree-ssa/pr96685-1.c: New test. * gcc.dg/tree-ssa/pr96685-2.c: New test. * gcc.dg/tree-ssa/pr96685-3.c: New test. --- gcc/match.pd | 28 ++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr96685-1.c | 52 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr96685-2.c | 40 +++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr96685-3.c | 43 +++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr96685-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr96685-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr96685-3.c diff --git a/gcc/match.pd b/gcc/match.pd index 43bacb4f68e..8f3edfa2fa6 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1074,6 +1074,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_not (plus:c (bit_not @0) @1)) (minus @0 @1)) +/* ~(X - Y) -> ~X + Y. */ +(simplify + (bit_not (minus:s @0 @1)) + (plus (bit_not @0) @1)) +(simplify + (bit_not (plus:s @0 INTEGER_CST@1)) + (if ((INTEGRAL_TYPE_P (type) + && TYPE_UNSIGNED (type)) + || (!TYPE_OVERFLOW_SANITIZED (type) + && may_negate_without_overflow_p (@1))) + (plus (bit_not @0) { const_unop (NEGATE_EXPR, type, @1); }))) + +#if GIMPLE +/* ~X + Y -> (Y - X) - 1. */ +(simplify + (plus:c (bit_not @0) @1) + (if (ANY_INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_WRAPS (type) + /* -1 - X is folded to ~X, so we'd recurse endlessly. */ + && !integer_all_onesp (@1)) + (plus (minus @1 @0) { build_minus_one_cst (type); }) + (if (INTEGRAL_TYPE_P (type) + && TREE_CODE (@1) == INTEGER_CST + && wi::to_wide (@1) != wi::min_value (TYPE_PRECISION (type), + SIGNED)) + (minus (plus @1 { build_minus_one_cst (type); }) @0)))) +#endif + /* x + (x & 1) -> (x + 1) & ~1 */ (simplify (plus:c @0 (bit_and:s @0 integer_onep@1)) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96685-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96685-1.c new file mode 100644 index 00000000000..eb3b1ea8dd6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96685-1.c @@ -0,0 +1,52 @@ +/* PR tree-optimization/96685 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 1;" 6 "optimized" } } */ + +unsigned +f1 (unsigned x, unsigned y) +{ + unsigned a = ~(x - y); + unsigned b = ~x + y; + return a == b; +} + +unsigned +f2 (unsigned x) +{ + unsigned a = ~(x + -124U); + unsigned b = ~x + 124U; + return a == b; +} + +unsigned +f3 (unsigned x) +{ + unsigned a = ~(x + 124U); + unsigned b = ~x + -124U; + return a == b; +} + +int +f4 (int x, int y) +{ + int a = ~(x - y); + int b = ~x + y; + return a == b; +} + +int +f5 (int x) +{ + int a = ~(x + -124); + int b = ~x + 124; + return a == b; +} + +int +f6 (int x) +{ + int a = ~(x + 124); + int b = ~x + -124; + return a == b; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96685-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96685-2.c new file mode 100644 index 00000000000..e3c1ac79ff4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96685-2.c @@ -0,0 +1,40 @@ +/* PR tree-optimization/96685 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 1;" 4 "optimized" } } */ + +int +f1 (unsigned x, unsigned y) +{ + unsigned int r1 = (x - y); + r1 = ~r1; + unsigned int r2 = ~(x - y); + return r1 == r2; +} + +int +f2 (unsigned x, unsigned y) +{ + unsigned int r1 = (x - 23); + r1 = ~r1; + unsigned int r2 = ~(x - 23); + return r1 == r2; +} + +int +f3 (int x, int y) +{ + int r1 = (x - y); + r1 = ~r1; + int r2 = ~(x - y); + return r1 == r2; +} + +int +f4 (int x, int y) +{ + int r1 = (x - 23); + r1 = ~r1; + int r2 = ~(x - 23); + return r1 == r2; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96685-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96685-3.c new file mode 100644 index 00000000000..b3c185530bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96685-3.c @@ -0,0 +1,43 @@ +/* PR tree-optimization/96685 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-times "return 1;" 4 "optimized" } } */ + +int +f1 (unsigned x, unsigned y) +{ + unsigned int r1 = (x - y); + r1 = ~r1; + unsigned int r2 = (y - x); + r2 = r2 - 1; + return r1 == r2; +} + +int +f2 (unsigned x, unsigned y) +{ + unsigned int r1 = (x - 23); + r1 = ~r1; + unsigned int r2 = (23 - x); + r2 = r2 - 1; + return r1 == r2; +} + +int +f3 (int x, int y) +{ + int r1 = (x - 23); + r1 = ~r1; + int r2 = (23 - x); + --r2; + return r1 == r2; +} + +int +f4 (int x, int y) +{ + int r1 = (x - 23); + r1 = ~r1; + int r2 = (22 - x); + return r1 == r2; +} -- 2.30.2