RTL is able to do this optimization but doing it earlier on gimple
can promote further optimizations during tree-opt.
The achieved result is mostly positive with a handful of tests
reporting optimizations being done earlier. The pattern is being
matched during forwprop so this is an expected result.
A not so good result is pr92080-12.c, where two extra insns ended up
being added in the expected function scanner. The test seems to care
just with the cfi_* labels so I updated it with the new asm. The reason
we have extra insns added in the asm seems to be slp being able to
reduce the original code better than what I'm doing with match.pd,
something that I'm not sure if it's expected/acceptable, or a problem
with this match.pd pattern or anything else.
Boostrapped and regression tested in x86_64 and aarch64.
PR tree-optimization/126523
gcc/ChangeLog:
* match.pd(`(convert (bit_not (convert A)))`): New pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr112095.c: 'bf' is now also being simplified
to "return a"
* gcc.dg/vect/pr113281-5.c: The signed:16 narrowing in 'f1' is
now done before the vectorizer
* gcc.target/i386/pr92080-12.c: Two extra insns ('incl and
notl') added in the function body.
* gcc.dg/tree-ssa/pr126523.c: New test.
---
gcc/match.pd | 44 ++++++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr112095.c | 3 +-
gcc/testsuite/gcc.dg/tree-ssa/pr126523.c | 52 ++++++++++++++++++++++
gcc/testsuite/gcc.dg/vect/pr113281-5.c | 1 -
gcc/testsuite/gcc.target/i386/pr92080-12.c | 4 +-
5 files changed, 101 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126523.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 2d1161b860b..f64238001c3 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -13384,6 +13384,50 @@ and,
&& !TYPE_OVERFLOW_SANITIZED (TREE_TYPE (@0)))
(convert @0)))
+/* PR126523: (convert (~(convert A))); */
+(simplify
+ (convert (bit_not@2 (convert@1 @0)))
+ (if (INTEGRAL_TYPE_P (type)
+ && INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && single_use (@1)
+ && single_use (@2)
+ && TYPE_SIGN (type) == TYPE_SIGN (TREE_TYPE (@0)))
+ (with {
+ tree orig_type = TREE_TYPE (@0);
+ tree inner_type = TREE_TYPE (@1);
+ unsigned orig_prec = TYPE_PRECISION (orig_type);
+ unsigned inner_prec = TYPE_PRECISION (inner_type);
+ unsigned outer_prec = TYPE_PRECISION (type);
+ }
+ /* We can't simplify the following cases:
+
+ - an inner widening followed by an outer widening. The
+ inner widening add bits that won't be eliminated by
+ the outer cast, i.e. (convert (bit_not A)) will have
+ less original A bits;
+
+ - an inner narrowing that is shorter than the outer
+ convert. Bits from A will be chopped from the end
+ result and (convert (bit_not A)) will end up having
+ more original A bits. */
+ (if (!(inner_prec > orig_prec
+ && outer_prec > orig_prec)
+ && !(inner_prec < orig_prec
+ && inner_prec < outer_prec))
+
+ /* Simplify these to (bit_not (convert:type A)) where 'type' is
+ either the same prec or a narrowing type. */
+ (if (outer_prec <= orig_prec)
+ (bit_not (convert @0))
+
+ /* For widening converts we must be sure that we don't have a
+ sign change in the middle. Otherwise this simplification
+ will be different than the original due to sign/zero extension
+ bits from the widening affecting the result. */
+ (if (TYPE_SIGN (inner_type) == TYPE_SIGN (orig_type))
+ (convert (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/pr112095.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr112095.c
index f3080c1e476..d63aacc94c6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr112095.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr112095.c
@@ -121,7 +121,8 @@ vg (v4ui a, v4ui b)
}
/* f* and vf should simplify to return a. */
-/* { dg-final { scan-tree-dump-times "return a_|<retval> = a_" 6 "release_ssa"
} } */
+/* after 126523 bf is also simplified to return a. */
+/* { dg-final { scan-tree-dump-times "return a_|<retval> = a_" 7 "release_ssa"
} } */
/* g* and vg should simplify to ~a directly. */
/* { dg-final { scan-tree-dump-times "= ~a" 6 "release_ssa" } } */
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..a3c251aa1a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126523.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+typedef signed char int8;
+typedef signed short int16;
+typedef signed int int32;
+
+int32 f1 (int32 a)
+{
+ uint32 t = a;
+ t = ~t;
+ int32 a1 = t;
+ return a1;
+}
+int32 f1_2 (int32 a) { return ~a; }
+int f1_res (int32 a) { return f1 (a) == f1_2 (a);}
+
+int16 f2 (int16 a)
+{
+ uint32 t = a;
+ t = ~t;
+ int16 a1 = t;
+ return a1;
+}
+int16 f2_2 (int16 a) { return ~a; }
+int f2_res (int16 a) { return f2 (a) == f2_2 (a);}
+
+int8 f3 (int16 a)
+{
+ uint16 t = a;
+ t = ~t;
+ int8 a1 = t;
+ return a1;
+}
+int8 f3_2 (int16 a) { return ~(int8)a; }
+int f3_res (int16 a) { return f3 (a) == f3_2 (a);}
+
+uint8 f4 (uint16 a)
+{
+ int32 t = a;
+ t = ~t;
+ uint8 a1 = t;
+ return a1;
+}
+uint8 f4_2 (uint16 a) { return ~(uint8)a; }
+int f4_res (uint16 a) { return f4 (a) == f4_2 (a);}
+
+/* { dg-final { scan-tree-dump-times " return 1;" 4 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr113281-5.c
b/gcc/testsuite/gcc.dg/vect/pr113281-5.c
index 756bf21c380..0f51c82c6fc 100644
--- a/gcc/testsuite/gcc.dg/vect/pr113281-5.c
+++ b/gcc/testsuite/gcc.dg/vect/pr113281-5.c
@@ -61,4 +61,3 @@ f5 (void)
}
/* { dg-final { scan-tree-dump {can narrow to signed:17 without loss [^\n]+=
-} "vect" } } */
-/* { dg-final { scan-tree-dump {can narrow to signed:16 without loss [^\n]+=
~} "vect" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr92080-12.c
b/gcc/testsuite/gcc.target/i386/pr92080-12.c
index 61630953022..655520502d8 100644
--- a/gcc/testsuite/gcc.target/i386/pr92080-12.c
+++ b/gcc/testsuite/gcc.target/i386/pr92080-12.c
@@ -11,9 +11,11 @@
** testl %edi, %edi
** je .L3
** movl %edi, %eax
+** incl %edi
+** notl %edi
+** negl %eax
** andl \$1, %edi
** negl %edi
-** negl %eax
** andl %esi, %edi
** xorb %dil, a\(%rip\)
** ret
--
2.43.0