match.pd: Add ~(X - Y) -> ~X + Y simplification [PR96685]
authorJakub Jelinek <jakub@redhat.com>
Sat, 12 Dec 2020 13:49:57 +0000 (14:49 +0100)
committerJakub Jelinek <jakub@redhat.com>
Sat, 12 Dec 2020 13:49:57 +0000 (14:49 +0100)
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  <jakub@redhat.com>

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
gcc/testsuite/gcc.dg/tree-ssa/pr96685-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr96685-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr96685-3.c [new file with mode: 0644]

index 43bacb4f68e2cb5b4557a45ab4ca42f0d2b473c3..8f3edfa2fa62845cdf6ac4f71e49510399e08aea 100644 (file)
@@ -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 (file)
index 0000000..eb3b1ea
--- /dev/null
@@ -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 (file)
index 0000000..e3c1ac7
--- /dev/null
@@ -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 (file)
index 0000000..b3c1855
--- /dev/null
@@ -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;
+}