https://gcc.gnu.org/g:7f3d7bbf2c6a826222af622e9700193ca9afd86c

commit r17-5414-g7f3d7bbf2c6a826222af622e9700193ca9afd86c
Author: Igor Shevlyakov <[email protected]>
Date:   Thu Oct 15 10:58:16 2026 -0700

    match.pd: Recognise the signbit-based copysign idiom
    
    The pattern added for PR109843 folds
    
        (signbit (x) != 0) == (signbit (y) != 0) ? y : -y
    
    and its variants to copysign.  C code using the <math.h> signbit macro
    usually compares the raw values instead,
    
        signbit (x) == signbit (y) ? y : -y
    
    and that is still emitted as a sign test, a branch and a negate.
    
    signbit only promises a nonzero value for a negative argument, so the
    comparison is unspecified when both arguments are negative, and GCC
    does produce different values: the constant folder and ranger give 1,
    while expand_builtin_signbit without a signbit optab gives the masked
    sign bit.  The fold, for == and != alike, takes the two nonzero values
    to be equal, which is one of the allowed choices.
    
    Add the raw comparison next to the PR109843 pattern, with the same
    guards.  As copysign only changes the sign bit, the fold is exact for
    signed zeros, infinities and NaNs and does not need -ffast-math.
    
    Assisted-by: Claude Opus 5.5
    
    gcc/ChangeLog:
    
            * match.pd (signbit (x) cmp signbit (y) ? y : -y): New
            simplification.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/copysign-signbit.c: New test.
    
    Signed-off-by: Igor Shevlyakov <[email protected]>

Diff:
---
 gcc/match.pd                                     | 15 +++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/copysign-signbit.c | 32 ++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/gcc/match.pd b/gcc/match.pd
index f3d9e55f1390..2bb64104aa38 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -10737,6 +10737,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       (if ((cmp == EQ_EXPR) == (icmp1 == icmp2))
        (IFN_COPYSIGN @1 @0)
        (IFN_COPYSIGN @1 (negate @0)))))))))
+
+/* signbit (x) cmp signbit (y) ? y : -y -> copysign (y, +-x).  The nonzero
+   value of signbit is unspecified, so the comparison is too when both x
+   and y are negative; the fold takes the two values to be equal.  */
+(for cmp (eq ne)
+ (for sign (SIGNBIT)
+  (simplify
+   (cond (cmp:c (sign @0) (sign @1)) @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)
+     (IFN_COPYSIGN @1 @0)
+     (IFN_COPYSIGN @1 (negate @0)))))))
 #endif
 
 (simplify
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copysign-signbit.c 
b/gcc/testsuite/gcc.dg/tree-ssa/copysign-signbit.c
new file mode 100644
index 000000000000..e005d4c9819c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/copysign-signbit.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-additional-options "-msse2 -mfpmath=sse" { target { { i?86-*-* 
x86_64-*-* } && ilp32 } } } */
+
+/* signbit (x) cmp signbit (y) ? y : -y is copysign (y, +-x).  */
+
+double d_eq (double x, double y)
+{ return __builtin_signbit (x) == __builtin_signbit (y) ? y : -y; }
+
+double d_eq_swapped (double x, double y)
+{ return __builtin_signbit (y) == __builtin_signbit (x) ? y : -y; }
+
+double d_ne (double x, double y)
+{ return __builtin_signbit (x) != __builtin_signbit (y) ? -y : y; }
+
+double d_if (double x, double y)
+{
+  if (__builtin_signbit (x) == __builtin_signbit (y))
+    return y;
+  return -y;
+}
+
+float f_eq (float x, float y)
+{ return __builtin_signbitf (x) == __builtin_signbitf (y) ? y : -y; }
+
+/* copysign (y, -x).  */
+
+double d_neg (double x, double y)
+{ return __builtin_signbit (x) != __builtin_signbit (y) ? y : -y; }
+
+/* { dg-final { scan-tree-dump-times " = \\.COPYSIGN " 6 "optimized" { target 
ifn_copysign } } } */
+/* { dg-final { scan-tree-dump-not "signbit" "optimized" { target ifn_copysign 
} } } */

Reply via email to