On Tue, Jul 14, 2026 at 8:55 AM Naveen
<[email protected]> wrote:
>
> PHI-OPT fails to simplify conditional accumulation of an absolute value:
> if (x >= 0)
> y += x;
> else
> y -= x;
>
> For signed integral types, perform the addition in the corresponding
> unsigned type and convert the result back to the original type. This
> avoids introducing signed overflow and preserves wrapping semantics
> including when X is TYPE_MIN_VALUE. Do not apply the transformation
> when signed overflow traps or is sanitized.
>
> gcc/ChangeLog:
> PR tree-optimization/56223
> * match.pd (X >=/> 0 ? Y + X : Y - X): New simplification.
> (X <=/< 0 ? Y - X : Y + X): Likewise.
>
> gcc/testsuite/ChangeLog:
> PR tree-optimization/56223
> * gcc.dg/tree-ssa/pr56223.c: New test.
> * gcc.dg/tree-ssa/pr56223-2.c: New test.
>
> Signed-off-by: Naveen <[email protected]>
> ---
> gcc/match.pd | 35 +++++++++++++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c | 39 +++++++++++++++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr56223.c | 46 +++++++++++++++++++++++
> 3 files changed, 120 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index d1a12c35ed3..70005a6fda2 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -7243,6 +7243,41 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> )
> )
>
> +
> + /* X >=/> 0 ? Y + X : Y - X same as Y + abs (X).
> + Build the addition in an unsigned type for integral types so the
> + replacement does not introduce signed overflow. */
> + (for cmp (ge gt)
> + (simplify
> + (cond (cmp @0 integer_zerop) (plus:c @0 @1) (minus @1 @0))
> + (if (INTEGRAL_TYPE_P (type)
> + && types_match (type, @0)
> + && types_match (type, @1)
> + && !TYPE_UNSIGNED (type)
> + && !TYPE_OVERFLOW_TRAPS (type)
> + && !TYPE_OVERFLOW_SANITIZED (type))
> + (with {
> + tree utype = unsigned_type_for (type);
> + }
> + (convert (plus:utype (convert:utype @1) (absu:utype @0)))))))
> +
> + /* X <=/< 0 ? Y - X : Y + X same as Y + abs (X).
> + Build the addition in an unsigned type for integral types so the
> + replacement does not introduce signed overflow. */
> + (for cmp (le lt)
> + (simplify
> + (cond (cmp @0 integer_zerop) (minus @1 @0) (plus:c @0 @1))
you should be able to merge the patterns with additional lock-step for
for the arithmetic ops like
(for cmp (ge gt le lt)
true_op (plus plus minus minus)
false_op (minus minus plus plus)
> + (if (INTEGRAL_TYPE_P (type)
> + && types_match (type, @0)
> + && types_match (type, @1)
this should be given, no need to check.
What about X <=/< 0 ? Y + X : Y - X? That
should be the same as Y - abs (X), no? Similar for the reverse
compare case. Bonus point to handle that as well?
> + && !TYPE_UNSIGNED (type)
> + && !TYPE_OVERFLOW_TRAPS (type)
> + && !TYPE_OVERFLOW_SANITIZED (type))
> + (with {
> + tree utype = unsigned_type_for (type);
> + }
> + (convert (plus:utype (convert:utype @1) (absu:utype @0)))))))
> +
> /* -(type)!A -> (type)A - 1. */
> (simplify
> (negate (convert?:s (logical_inverted_value:s @0)))
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
> new file mode 100644
> index 00000000000..76ce731ad76
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
> @@ -0,0 +1,39 @@
> +/* PR tree-optimization/56223 */
> +/* Verify wrapping and INT_MIN behavior of the ABSU-based replacement. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fwrapv" } */
> +
> +#define INT_MAX __INT_MAX__
> +#define INT_MIN (-INT_MAX - 1)
> +
> +__attribute__((noipa)) int
> +f (int s, int x)
> +{
> + if (x >= 0)
> + s += x;
> + else
> + s -= x;
> + return s;
> +}
> +
> +int
> +main (void)
> +{
> + if (f (10, 4) != 14)
> + __builtin_abort ();
> +
> + if (f (10, -4) != 14)
> + __builtin_abort ();
> +
> + if (f (INT_MIN, INT_MIN) != 0)
> + __builtin_abort ();
> +
> + if (f (INT_MAX, 1) != INT_MIN)
> + __builtin_abort ();
> +
> + if (f (0, INT_MIN) != INT_MIN)
> + __builtin_abort ();
> +
> + return 0;
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
> new file mode 100644
> index 00000000000..36e3c50f2d4
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
> @@ -0,0 +1,46 @@
> +/* PR tree-optimization/56223 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-phiopt2" } */
> +
> +int
> +f_ge (int s, int x)
> +{
> + if (x >= 0)
> + s += x;
> + else
> + s -= x;
> + return s;
> +}
> +
> +int
> +f_gt (int s, int x)
> +{
> + if (x > 0)
> + s += x;
> + else
> + s -= x;
> + return s;
> +}
> +
> +int
> +f_le (int s, int x)
> +{
> + if (x <= 0)
> + s -= x;
> + else
> + s += x;
> + return s;
> +}
> +
> +int
> +f_lt (int s, int x)
> +{
> + if (x < 0)
> + s -= x;
> + else
> + s += x;
> + return s;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "ABSU_EXPR" 4 "phiopt2" } } */
> +/* { dg-final { scan-tree-dump-not "if " "phiopt2" } } */
> --
> 2.34.1
>