On Thu, Sep 24, 2026 at 2:45 PM Daniel Henrique Barboza
<[email protected]> wrote:
>
>
>
> 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.
The problem is obvious for me:
typedef char int8_t;
Here int8_t is unsigned for aarch64 and signed for x86.
You need to specify `signed char` instead of a plain char or use the
option -fsigned-char :).
Thanks,
Andrea
>
>
> 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
> >>
>