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. NaNs stay honored. 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-53.c: New test.
---
gcc/match.pd | 20 +++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/abs-5.c | 24 +++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c | 34 ++++++++++++++++++++++
3 files changed, 78 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..7bf4d9e618c 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7858,6 +7858,26 @@ 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. */
+ (for cmp (lt le)
+ (simplify
+ (cnd (cmp @0 real_zerop) (negate @0) @0)
+ (if (!HONOR_SIGNED_ZEROS (type)
+ && (!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)
+ && (!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..54b2dc40def
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/abs-5.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -fdump-tree-optimized" } */
+
+/* Fold, when signed zeros need not be preserved:
+ A </<= 0 ? -A : A -> ABS (A)
+ A >/>= 0 ? -A : A -> -ABS (A)
+
+ Matched directly. With NaNs honored, < cannot be inverted: its
+ inverse is UNGE, and UNGE does not raise invalid. 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..7483c574c6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-53.c
@@ -0,0 +1,34 @@
+/* { dg-options "-O2 -fno-signed-zeros -fdump-tree-phiopt" } */
+
+/* Swapped arms of phi-opt-24.c. A < 0 ? -A : A is abs (A).
+ A floating compare that may trap on NaNs is not inverted into the
+ A >= 0 ? A : -A form, 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