Fold (signbit (x) cmp1 0) cmp (signbit (y) cmp2 0) ? y : -y
to copysign (y, +-x). The result keeps the magnitude of Y and takes its
sign from X (or -X). Emitted as IFN_COPYSIGN when the target supports it.
PR tree-optimization/109843
gcc/ChangeLog:
* match.pd ((signbit (x) cmp 0) cmp (signbit (y) cmp 0) ? y : -y):
New simplification to copysign (y, +-x).
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr109843.c: New test.
Signed-off-by: Eikansh Gupta <[email protected]>
---
gcc/match.pd | 21 +++++++
gcc/testsuite/gcc.dg/tree-ssa/pr109843.c | 76 ++++++++++++++++++++++++
2 files changed, 97 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr109843.c
diff --git a/gcc/match.pd b/gcc/match.pd
index d1a12c35ed3..eb2687976d3 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -9864,6 +9864,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(abs @0)
(negate (abs @0))))))
+/* (signbit (x) cmp1 0) cmp (signbit (y) cmp2 0) ? y : -y
+ -> copysign (y, +-x). */
+#if GIMPLE
+(for cmp (eq ne)
+ (for icmp1 (eq ne)
+ (for icmp2 (eq ne)
+ (for sign (SIGNBIT)
+ (simplify
+ (cond (cmp:c (icmp1 (sign @0) integer_zerop)
+ (icmp2 (sign @1) integer_zerop))
+ @1 (negate @1))
+ (if (SCALAR_FLOAT_TYPE_P (type)
+ && types_match (type, TREE_TYPE (@0))
+ && direct_internal_fn_supported_p (IFN_COPYSIGN, type,
+ OPTIMIZE_FOR_BOTH))
+ (if ((cmp == EQ_EXPR && icmp1 == icmp2)
+ || (cmp == NE_EXPR && icmp1 != icmp2))
+ (IFN_COPYSIGN @1 @0)
+ (IFN_COPYSIGN @1 (negate @0)))))))))
+#endif
+
(simplify
/* signbit(x) -> 0 if x is nonnegative. */
(SIGNBIT tree_expr_nonnegative_p@0)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr109843.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr109843.c
new file mode 100644
index 00000000000..a7138ee5817
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr109843.c
@@ -0,0 +1,76 @@
+/* PR tree-optimization/109843 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <stdbool.h>
+
+/* Transforms to copysign (y, x) */
+
+float copysign1 (float x, float y)
+{
+ bool t = __builtin_signbit (x) == 0;
+ bool t1 = __builtin_signbit (y) == 0;
+ return (t == t1) ? y : -y;
+}
+
+float copysign2 (float x, float y)
+{
+ bool t = __builtin_signbit (x) != 0;
+ bool t1 = __builtin_signbit (y) != 0;
+ return (t == t1) ? y : -y;
+}
+
+float copysign3 (float x, float y)
+{
+ bool t = __builtin_signbit (x) != 0;
+ bool t1 = __builtin_signbit (y) == 0;
+ return (t != t1) ? y : -y;
+}
+
+float copysign4 (float x, float y)
+{
+ bool t = __builtin_signbit (x) == 0;
+ bool t1 = __builtin_signbit (y) != 0;
+ return (t != t1) ? y : -y;
+}
+
+float copysign5 (float x, float y)
+{
+ bool t = __builtin_signbit (y) == 0;
+ bool t1 = __builtin_signbit (x) == 0;
+ return (t == t1) ? y : -y;
+}
+
+/* Transforms to copysign (y, -x) */
+
+float copysign6 (float x, float y)
+{
+ bool t = __builtin_signbit (x) == 0;
+ bool t1 = __builtin_signbit (y) == 0;
+ return (t != t1) ? y : -y;
+}
+
+float copysign7 (float x, float y)
+{
+ bool t = __builtin_signbit (x) != 0;
+ bool t1 = __builtin_signbit (y) == 0;
+ return (t == t1) ? y : -y;
+}
+
+float copysign8 (float x, float y)
+{
+ bool t = __builtin_signbit (x) == 0;
+ bool t1 = __builtin_signbit (y) != 0;
+ return (t == t1) ? y : -y;
+}
+
+float copysign9 (float x, float y)
+{
+ bool t = __builtin_signbit (x) != 0;
+ bool t1 = __builtin_signbit (y) != 0;
+ return (t != t1) ? y : -y;
+}
+
+/* { dg-final { scan-tree-dump-not "signbit" "optimized" { target ifn_copysign
} } } */
+/* { dg-final { scan-tree-dump-times "= \\.COPYSIGN" 9 "optimized" { target
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-times " = -" 4 "optimized" { target
ifn_copysign } } } */
--
2.34.1