On Tue, May 19, 2026 at 6:18 AM Avinal Kumar <[email protected]> wrote:
>
> The pattern X != C1 ? -X : C2 currently exits when C1 is
> INT_MIN and the type doesn't wrap, because a signed negation
> of INT_MIN is undefined behavior.  But the whole expression is
> well-defined, it is equivalent to (signed)(-(unsigned)X).
>
> Handle the wi::only_sign_bit_p case by emitting an unsigned
> negate instead of giving up, copying what the abs pattern
> already does for the same edge case.
>
>         PR tree-optimization/125050
>
> gcc/ChangeLog:
>
>         * match.pd: (X != C1 ? -X : C2): Handle C1 being INT_MIN
>         by emitting (signed)(-(unsigned)X) instead of bailing out.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.dg/pr125050.c: New test.
>         * gcc.dg/tree-ssa/phi-opt-50.c: New test.
>         * gcc.dg/tree-ssa/phi-opt-51.c: New test.
>
> Signed-off-by: Avinal Kumar <[email protected]>
> ---
> Build and ran full testsuite on AMD64 machine.
>
> Changes from v1:
> Fixed the typo. Also found two whitespace issue, fixed them too.
>
>  gcc/match.pd                               | 12 ++++++++----
>  gcc/testsuite/gcc.dg/pr125050.c            | 13 +++++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c | 21 +++++++++++++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c | 21 +++++++++++++++++++++
>  4 files changed, 63 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/pr125050.c
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index ff13a07ea94..9fca662a2e4 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -6755,14 +6755,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>  )
>  #endif
>
> -/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2.  */
> +/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2.  Additionally,
> +   when C1 is the minimum signed value (e.g INT_MIN), -X would be
> +   undefined for signed types, so emit (signed)(-(unsigned)X) instead.  */
>  (simplify
>   (cond (ne @0 INTEGER_CST@1) (negate@3 @0) INTEGER_CST@2)
>   (if (!TYPE_SATURATING (type)
> -      && (TYPE_OVERFLOW_WRAPS (type)
> -         || !wi::only_sign_bit_p (wi::to_wide (@1)))
>        && wi::eq_p (wi::neg (wi::to_wide (@1)), wi::to_wide (@2)))
> -  @3))
> +  (if (TYPE_OVERFLOW_WRAPS (type)
> +       || !wi::only_sign_bit_p (wi::to_wide (@1)))
> +   @3
> +   (with {tree utype = unsigned_type_for (TREE_TYPE (@0)); }
> +    (convert (negate (convert:utype @0)))))))
>
>  /* X != C1 ? ~X : C2 simplifies to ~X when ~C1 == C2.  */
>  (simplify
> diff --git a/gcc/testsuite/gcc.dg/pr125050.c b/gcc/testsuite/gcc.dg/pr125050.c
> new file mode 100644
> index 00000000000..cf73d200cd5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr125050.c
> @@ -0,0 +1,13 @@
> +/* PR tree-optimization/125050 */
> +/* { dg-do compile } */
> +/* { dg-options "O1 -fdump-tree-phiopt1" } */
> +
> +int f(int a)
> +{
> +  if (a == -__INT_MAX__ - 1)
> +    return -__INT_MAX__ - 1;
> +  return -a;
> +}
> +
> +/* This should be converted to (int)(-(unsigned)a).  */
> +/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
> new file mode 100644
> index 00000000000..f386c25a61b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
> @@ -0,0 +1,21 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O1 -fdump-tree-phiopt1" } */
> +
> +/* a == INT_MIN ? INT_MIN : -a simplifies to  (int)(-(unsigned)a) */
> +int f1(int a)
> +{
> +  if (a == -__INT_MAX__ - 1)
> +    return -__INT_MAX__ - 1;
> +  return -a;
> +}
> +
> +/* a != INT_MIN ? -a : INT_MIN simplifies to  (int)(-(unsigned)a) */
> +int f2(int a)
> +{
> +  if (a != -__INT_MAX__ - 1)
> +    return -a;
> +  return -__INT_MAX__ - 1;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt1" } } */

This will fail since negate_expr won't match anywhere because you are
not using the -raw option to the dump file.

> +/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */

But with -raw, then the above will work by accident. It should be
matching "gimple_cond <".

> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
> new file mode 100644
> index 00000000000..952774e9840
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
> @@ -0,0 +1,21 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O1 -fdump-tree-phiopt1" } */
> +
> +/* Try the same pattern with different integer types.  */
> +
> +short f_short(short a)
> +{
> +  if (a == (short)(-__SHRT_MAX__ - 1))
> +    return -__SHRT_MAX__ - 1;
> +  return -a;
> +}
> +
> +long long f_ll(long long a)
> +{
> +  if (a == -__LONG_LONG_MAX__ - 1)
> +    return -__LONG_LONG_MAX__ - 1;
> +  return -a;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt1" } } */
> +/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */

Likewise.

With these 2 failures I am not very confident you tested the testcases
and/or the patch.

See 
http://54.172.246.49:9090/jobs/tcwg_gcc_check--master-arm-precommit/builds/10396/archive/artifacts/artifacts.precommit/notify/mail-body.txt
also for other failures.

Looks like gcc.dg/fold-condneg-2.c needs to be updated since we
produce the correct result of casting to unsigned first.

Thanks,
Andrea

> --
> 2.54.0
>

Reply via email to