RTL is able to do this optimization but doing it earlier on gimple
can promote further optimizations during tree-opt.
Boostrapped and regression tested in x86_64 and aarch64.
PR tree-optimization/126523
gcc/ChangeLog:
* match.pd(`(SIGNED (bit_not (UNSIGNED signed_var)))`): New
pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr126523.c: New test.
---
gcc/match.pd | 14 +++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr126523.c | 26 ++++++++++++++++++++++++
2 files changed, 40 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126523.c
diff --git a/gcc/match.pd b/gcc/match.pd
index e59c11d5d13..2b3713e7360 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -13279,6 +13279,20 @@ and,
&& !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)))
(convert @0)))
+/* PR126523: (SIGNED (~(UNSIGNED signed_var))) -> ~signed_var. */
+(simplify
+ (convert (bit_not (convert@1 @0)))
+ (if (INTEGRAL_TYPE_P (type)
+ && !TYPE_UNSIGNED (type)
+ && TREE_TYPE (@0) == type
+ && TYPE_UNSIGNED (TREE_TYPE (@1))
+ /* Check single_use since we're getting rid of @1. */
+ && single_use (@1)
+ /* The unsigned convert cannot have less bits
+ than the signed result. */
+ && TYPE_PRECISION (TREE_TYPE (@1)) >= TYPE_PRECISION (type))
+ (bit_not @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/pr126523.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr126523.c
new file mode 100644
index 00000000000..a8199c0b7ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126523.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+typedef int si;
+typedef unsigned ui;
+
+si f(si a)
+{
+ ui t = a;
+ t = ~t;
+ si a1 = t;
+ return a1;
+}
+
+si f1(si a)
+{
+ return ~a;
+}
+
+/* If everything went as planned g()
+ will reduce to 'return 1'. */
+int g(si a)
+{
+ return f(a) + f1(a) == (si)(2*(~a));
+}
+/* { dg-final { scan-tree-dump-times " return 1;" 1 "optimized" } } */
--
2.43.0