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 the operand cannot be a
NaN, or when the invalid exception is not observable.  A conversion
from an integer cannot be a NaN.  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/abs-6.c: New test.
        * testsuite/gcc.dg/tree-ssa/phi-opt-53.c: New test.
---
 gcc/match.pd                               | 24 +++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/abs-5.c      | 28 +++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/abs-6.c      | 13 ++++++++
 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c | 35 ++++++++++++++++++++++
 4 files changed, 100 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/abs-5.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/abs-6.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 1cb710974f7..4ab9bc9d6f0 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7858,6 +7858,30 @@ 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 this operand cannot be a NaN or the invalid
+    exception is not observable.  */
+ (for cmp (lt le)
+  (simplify
+   (cnd (cmp @0 real_zerop) (negate @0) @0)
+    (if (!HONOR_SIGNED_ZEROS (type)
+        && !(tree_expr_maybe_nan_p (@0) && flag_trapping_math)
+        && (!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)
+        && !(tree_expr_maybe_nan_p (@0) && 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..dcbf17f4023
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/abs-5.c
@@ -0,0 +1,28 @@
+/* { 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; }
+
+/* -ABS becomes .COPYSIGN (x, -1) when the target has the copysign optab.  */
+/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 4 "optimized" { target 
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-times "= \\.COPYSIGN" 2 "optimized" { target 
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 6 "optimized" { target { ! 
ifn_copysign } } } } */
+/* { 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/abs-6.c 
b/gcc/testsuite/gcc.dg/tree-ssa/abs-6.c
new file mode 100644
index 00000000000..83720813764
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/abs-6.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -fdump-tree-optimized" } */
+
+/* Trapping math stays on.  A float parameter can be a NaN, so the
+   ordered compare must not become ABS.  A conversion from an integer
+   cannot be a NaN, so that compare can.  */
+
+float keep_cmp (float a) { return a < 0 ? -a : a; }
+
+float from_int (int i) { return (float)i < 0 ? -(float)i : (float)i; }
+
+/* { dg-final { scan-tree-dump-times "= ABS_EXPR" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump " < " "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