On Wed, Oct 14, 2026 at 1:07 AM Alexey Lapshin
<[email protected]> wrote:
>
> PR tree-optimization/101039 folded A CMP 0 ? A : -A after that form
> was expanded into an if, by matching it in match.pd (r12-2041).  The
> true arm there is A and the false arm is -A.
>
> The swapped form still does not fold for floating point.  Integers
> reach the existing pattern by inverting the comparison.  A floating
> comparison that may trap on NaNs cannot be inverted: the inverse of
> < is UNGE, and UNGE does not raise invalid.
>
> Fold A </<= 0 ? -A : A to ABS (A) and A >/>= 0 ? -A : A to -ABS (A)
> when signed zeros need not be preserved.  ABS does not raise invalid,
> so the ordered compare is removed only when it cannot trap.  A NaN
> selects either arm, and both arms are NaNs.  Vectors are folded only
> when the target can do ABS (and NEGATE for the -ABS form).
>
> gcc:
>         * match.pd (A </<= 0 ? -A : A, A >/>= 0 ? -A : A): New patterns.
>         * testsuite/gcc.dg/tree-ssa/abs-5.c: New test.
>         * testsuite/gcc.dg/tree-ssa/phi-opt-46.c: New test.
> ---
>  gcc/match.pd                               | 23 ++++++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/abs-5.c      | 25 ++++++++++++++++
>  gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c | 35 ++++++++++++++++++++++
>  3 files changed, 83 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/abs-5.c
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c
>
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 6984af44582..ba421818284 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -7858,6 +7858,29 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>          (convert (negate (absu:utype (convert:stype @2))))))
>         (convert (negate (abs @2))))))
>   )
> + /* A </<= 0 ? -A : A    same as abs (A)
> +    A >/>= 0 ? -A : A    same as -abs (A)
> +    For integers these are reached by inverting the comparison of the
> +    forms above, but a floating-point comparison that may trap on NaNs
> +    cannot be inverted.  ABS does not trap, so the ordered compare may
> +    be removed only when it cannot raise invalid.  */
> + (for cmp (lt le)
> +  (simplify
> +   (cnd (cmp @0 real_zerop) (negate @0) @0)
> +    (if (!HONOR_SIGNED_ZEROS (type)
> +        && !(HONOR_NANS (type) && flag_trapping_math)

I was thinking tree_expr_maybe_nan_p rather than HONOR_NANS here.

> +        && (!VECTOR_TYPE_P (type)
> +            || target_supports_op_p (type, ABS_EXPR, optab_vector)))
> +     (abs @0))))
> + (for cmp (gt ge)
> +  (simplify
> +   (cnd (cmp @0 real_zerop) (negate @0) @0)
> +    (if (!HONOR_SIGNED_ZEROS (type)
> +        && !(HONOR_NANS (type) && flag_trapping_math)
> +        && (!VECTOR_TYPE_P (type)
> +            || (target_supports_op_p (type, ABS_EXPR, optab_vector)
> +                && target_supports_op_p (type, NEGATE_EXPR, optab_vector))))
> +     (negate (abs @0)))))
>
>   /* (A - B) == 0 ? (A - B) : (B - A)    same as (B - A) */
>   (for cmp (eq uneq)
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/abs-5.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/abs-5.c
> new file mode 100644
> index 00000000000..2891eb81e34
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/abs-5.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-signed-zeros -fno-trapping-math 
> -fdump-tree-optimized" } */
> +
> +/* Fold, when signed zeros need not be preserved:
> +     A </<= 0 ? -A : A  ->  ABS (A)
> +     A >/>= 0 ? -A : A  ->  -ABS (A)
> +
> +   ABS does not trap.  With NaNs honored, -fno-trapping-math is required
> +   so the ordered compare's invalid exception is not observable.  The
> +   compare is matched directly: its inverse is UNGE.  Both arms are NaN
> +   when A is NaN.  */
> +
> +float abs_lt (float a) { return a < 0 ? -a : a; }
> +float abs_le (float a) { return a <= 0 ? -a : a; }
> +float abs_if (float a) { if (a < 0) a = -a; return a; }
> +double abs_lt_d (double a) { return a < 0 ? -a : a; }
> +
> +float nabs_gt (float a) { return a > 0 ? -a : a; }
> +float nabs_ge (float a) { return a >= 0 ? -a : a; }
> +
> +/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 6 "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " < " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " <= " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " > " "optimized" } } */
> +/* { dg-final { scan-tree-dump-not " >= " "optimized" } } */
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c
> new file mode 100644
> index 00000000000..33a28d675b2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c
> @@ -0,0 +1,35 @@
> +/* { dg-options "-O2 -fno-signed-zeros -fno-trapping-math 
> -fdump-tree-phiopt" } */
> +
> +/* Swapped arms of phi-opt-24.c.  A < 0 ? -A : A is abs (A).
> +   ABS does not trap, so -fno-trapping-math is required while NaNs are
> +   honored.  A floating compare is not inverted into A >= 0 ? A : -A,
> +   so these folds need their own patterns.  */
> +
> +float f0(float A)
> +{
> +//     A < 0 ? -A : A    same as abs (A)
> +  if (A < 0)  return -A;
> +  return A;
> +}
> +float f1(float A)
> +{
> +//     A <= 0 ? -A : A    same as abs (A)
> +  if (A <= 0)  return -A;
> +  return A;
> +}
> +float f2(float A)
> +{
> +//     A > 0 ? -A : A    same as -abs (A)
> +  if (A > 0)  return -A;
> +  return A;
> +}
> +float f3(float A)
> +{
> +//     A >= 0 ? -A : A    same as -abs (A)
> +  if (A >= 0)  return -A;
> +  return A;
> +}
> +
> +/* f2 and f3 are -abs, not allowed in early phi-opt. */
> +/* { dg-final { scan-tree-dump-times "if" 2 "phiopt1" } } */
> +/* { dg-final { scan-tree-dump-not "if" "phiopt2" } } */
> --
> 2.55.0
>

Reply via email to