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