[gcc r17-2823] MATCH: fold signbit comparison and conditional negate to copysign [PR109843]

Eikansh Gupta via Gcc-cvs <[email protected]> Thu, 30 Jul 2026 10:39:41 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:1c8ca0108746d3a7452134f9d1c2e5d89857fed7

commit r17-2823-g1c8ca0108746d3a7452134f9d1c2e5d89857fed7
Author: Eikansh Gupta <[email protected]>
Date:   Wed Jun 17 09:58:16 2026 +0530

    MATCH: fold signbit comparison and conditional negate to copysign [PR109843]
    
    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]>

Diff:
---
 gcc/match.pd                             | 20 +++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr109843.c | 76 ++++++++++++++++++++++++++++++++
 2 files changed, 96 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index 782cfe7dc557..6c9bb0da7cf0 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -9846,6 +9846,26 @@ 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))
+       (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 000000000000..a7138ee58178
--- /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 } } } */