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
>

Reply via email to