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
>