On 9/21/2026 10:45 PM, Andrea Pinski wrote:
On Mon, Sep 21, 2026 at 4:45 AM Daniel Barboza
<[email protected]> wrote:

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

Hmm, a few things here.
`TREE_TYPE (@0) == type` should be `types_match (@0, type)` (this will
allow for more types matching in gimple).
We want to remove the converts if the inner and outer precisions are
the same irrespective of the signedness.
I think if the inner convert is a nop_convert, and the outer one is a
truncation, then we should emit `(convert (bit_not @0))`; I think you
want a single_use on the bit_not instead of the convert (nop_converts
are "free") and not need to check the type of @0 here.
For (trunc (bit_not (widdening @0))), it does not matter what the
signedness of @0 if precision of @0 matches the precision of the type
because the bits which either sign or zero extended (and then `not`ed)
will be truncated away.
So maybe types_match should really be tree_nop_conversion_p and keep
around the convert to type around @0 (for gimple, that will be removed
for the case of types_match).
Even more we can truncate further than @0 here too; so this should be
a TYPE_PRECISION check then.

I came up with a pattern that would cover more cases and managed to bootstrap
it in x86.  But then when I added more test coverage I realized that the
patterns weren't working ... in x86. They do work in aarch64.

Or so I thought.  In reality this code generates different Gimple between x86 
and
aarch64, on trunk.  Since my main dev machine is an aarch64 box I was misled
into thinking that my pattern was doing something.

Here's an example:

https://godbolt.org/z/59rzjs1a6

The aarch64 dumps have one less type cast than x86 in all the functions.


I played a bit to see which patterns aren't already optimized in aarch64 and
x86 and, so far, the only pattern that can be optimized by both happens to be
the one for the bug, i.e.  same precision conversions.


The pattern from this bug is covering signed -> unsigned -> signed only so I can
send a v2 that covers unsigned -> signed -> unsigned.  Aside from that I'm not 
sure
how to proceed with the other patterns.  Should we invest time in them given 
that
some targets are already doing a bit of the work in Gimple?  Should we optimize
these 2 patterns that we have in hand and open a new bug to see how to optimize
the rest?


Thanks,
Daniel







Thanks,
Andrea




+
  /* 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


Reply via email to