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

Reply via email to