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
>

Reply via email to