https://gcc.gnu.org/g:2fb55e1d061ab091beafa04b2050c88f8d8d64bf

commit r17-3158-g2fb55e1d061ab091beafa04b2050c88f8d8d64bf
Author: Roger Sayle <[email protected]>
Date:   Sun Aug 9 08:00:06 2026 +0200

    PR tree-optimization/126467: 0.0-x -> -x vs. signed zeros in match.pd.
    
    This is my proposed solution to PR tree-optimization/126467, where we're
    inappropriately converting 0.0 - x to -x when we honor IEEE signed zeros.
    This transformation is valid with -Ofast, but by default +0.0 - +0.0
    should return +0.0, but -(+0.0) is -0.0.  Likewise when x is NaN, 0.0 - x
    may change the payload, but -x is guaranteed not to.  My fix is to
    separate the logic for this transformation from that for FP addition.
    
    Technically, we could do slightly better by introducing a
    tree_expr_negative_p (complementing and mutually recursive with the
    existing tree_expr_nonnegative_p), but that's a bigger change and
    less suitable for backporting to release branches, i.e. a follow-up.
    
    I agree with Alexander Monakov that an alternate fix might be to
    correctly reuse the existing fold_real_zero_addition_p functionality
    by constructing and garbage collecting a NEGATE_EXPR tree on each call,
    but this seems a little less efficient.
    
    2026-08-09  Roger Sayle  <[email protected]>
                Andrea Pinski  <[email protected]>
    
    gcc/ChangeLog
            PR tree-optimization/126467
            * match.pd (0.0 - x -> -x): Update the conditions under which
            the transformation is performed, disallowing x = +0.0 when we
            honor signed zeros.  This is still disallowed if x is a NaN.
    
    gcc/testsuite/ChangeLog
            PR tree-optimization/126467
            * gcc.dg/pr126467-1.c: New test case.
            * gcc.dg/pr126467-2.c: Likewise.
            * gcc.dg/pr96392.c: Fix incorrect test case.

Diff:
---
 gcc/match.pd                      | 16 ++++++++++++----
 gcc/testsuite/gcc.dg/pr126467-1.c | 21 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr126467-2.c | 15 +++++++++++++++
 gcc/testsuite/gcc.dg/pr96392.c    |  5 -----
 4 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index 993faff2be33..1ea46fd17264 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6001,12 +6001,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (pointer_diff integer_zerop @1)
  (negate (convert @1)))
 
-/* (ARG0 - ARG1) is the same as (-ARG1 + ARG0).  So check whether
-   ARG0 is zero and X + ARG0 reduces to X, since that would mean
-   (-ARG1 + ARG0) reduces to -ARG1.  */
+/* (0.0 - ARG1) can be transformed to -ARG1, if we don't honor NaNs
+   and signed zeros or ARG1 is known to be non-zero.  Subtraction of
+   NaN may signal or modify payload, but negation doesn't, so it is
+   unsafe to apply this transformation for any kind of NaN.  When
+   ARG1 is +0.0 or -0.0, the behaviour depends upon the rounding
+   mode.  With the default rounding mode, (-0.0 - ARG1) is -ARG1,
+   but (+0.0 - ARG1) is only -ARG1 if ARG1 cannot be +0.0.  */
 (simplify
  (minus real_zerop@0 @1)
- (if (fold_real_zero_addition_p (type, @1, @0, 0))
+ (if (!tree_expr_maybe_nan_p (@1)
+      && (!HONOR_SIGNED_ZEROS (type)
+         || tree_expr_nonzero_p (@1)
+         || (!flag_rounding_math
+             && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@0)))))
   (negate @1)))
 
 /* Transform x * -1 into -x.  */
diff --git a/gcc/testsuite/gcc.dg/pr126467-1.c 
b/gcc/testsuite/gcc.dg/pr126467-1.c
new file mode 100644
index 000000000000..b078b4364544
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126467-1.c
@@ -0,0 +1,21 @@
+/* PR tree-optimization/126467 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-add-options ieee } */
+
+/* 0.0 - x is not -x.
+   For x == +0.0, +0.0 - +0.0 is +0.0, but -x is -0.0.
+   Likewise fabs/negate preserve a NaN's payload but
+   subtraction doesn't.  */
+
+double foo (double x)
+{
+  return 0.0 - x;
+}
+
+double bar (double y)
+{
+  return 0.0 - __builtin_fabs (y);
+}
+
+/* { dg-final { scan-tree-dump-times " \\- " 2 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr126467-2.c 
b/gcc/testsuite/gcc.dg/pr126467-2.c
new file mode 100644
index 000000000000..287425531736
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126467-2.c
@@ -0,0 +1,15 @@
+/* PR tree-optimization/126467 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -ffinite-math-only 
-fdump-tree-optimized" } */
+
+double foo (double x)
+{
+  return 0.0 - x;
+}
+
+double bar (double y)
+{
+  return 0.0 - __builtin_fabs (y);
+}
+
+/* { dg-final { scan-tree-dump-not " \\- " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr96392.c b/gcc/testsuite/gcc.dg/pr96392.c
index fb7de217f966..82756907f3ff 100644
--- a/gcc/testsuite/gcc.dg/pr96392.c
+++ b/gcc/testsuite/gcc.dg/pr96392.c
@@ -12,11 +12,6 @@ double sub0(int x)
   return x - 0.0;
 }
 
-double negate(int x)
-{
-  return 0.0 - x;
-}
-
 double subtract(int x)
 {
   return (double)x - (double)x;

Reply via email to