[match.pd PATCH] PR tree-optimization/126467: 0.0-x -> -x vs. signed zeros.
"Roger Sayle" <[email protected]> Wed, 5 Aug 2026 09:04:31 +0100
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
This is a multipart message in MIME format.
------=_NextPart_000_0032_01DD24B9.6E0A9580
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
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.
This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
and make -k check, both with and without --target_board=unix{-m32}
with no new failures. Ok for mainline?
2026-08-05 Roger Sayle <[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.
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.
------=_NextPart_000_0032_01DD24B9.6E0A9580
Content-Type: text/plain;
name="patchrn2.txt"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="patchrn2.txt"
diff --git a/gcc/match.pd b/gcc/match.pd=0A=
index 536d5125a0b..b69543f35f2 100644=0A=
--- a/gcc/match.pd=0A=
+++ b/gcc/match.pd=0A=
@@ -5910,12 +5910,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)=0A=
(pointer_diff integer_zerop @1)=0A=
(negate (convert @1)))=0A=
=0A=
-/* (ARG0 - ARG1) is the same as (-ARG1 + ARG0). So check whether=0A=
- ARG0 is zero and X + ARG0 reduces to X, since that would mean=0A=
- (-ARG1 + ARG0) reduces to -ARG1. */=0A=
+/* (0.0 - ARG1) can be transformed to -ARG1, if we don't honor NaNs=0A=
+ and signed zeros or ARG1 is known to be non-zero. Subtraction of=0A=
+ NaN may signal or modify payload, but negation doesn't, so it is=0A=
+ unsafe to apply this transformation for any kind of NaN. When=0A=
+ ARG1 is +0.0 or -0.0, the behaviour depends upon the rounding=0A=
+ mode. With the default rounding mode, (-0.0 - ARG1) is -ARG1,=0A=
+ but (+0.0 - ARG1) is only -ARG1 if ARG1 cannot be +0.0. */=0A=
(simplify=0A=
(minus real_zerop@0 @1)=0A=
- (if (fold_real_zero_addition_p (type, @1, @0, 0))=0A=
+ (if ((!HONOR_NANS (type) || !tree_expr_maybe_nan_p (@1))=0A=
+ && (!HONOR_SIGNED_ZEROS (type)=0A=
+ || tree_expr_nonzero_p (@1)=0A=
+ || (!flag_rounding_math=0A=
+ && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@0)))))=0A=
(negate @1)))=0A=
=0A=
/* Transform x * -1 into -x. */=0A=
diff --git a/gcc/testsuite/gcc.dg/pr126467-1.c =
b/gcc/testsuite/gcc.dg/pr126467-1.c=0A=
new file mode 100644=0A=
index 00000000000..b078b436454=0A=
--- /dev/null=0A=
+++ b/gcc/testsuite/gcc.dg/pr126467-1.c=0A=
@@ -0,0 +1,21 @@=0A=
+/* PR tree-optimization/126467 */=0A=
+/* { dg-do compile } */=0A=
+/* { dg-options "-O2 -fdump-tree-optimized" } */=0A=
+/* { dg-add-options ieee } */=0A=
+=0A=
+/* 0.0 - x is not -x.=0A=
+ For x =3D=3D +0.0, +0.0 - +0.0 is +0.0, but -x is -0.0.=0A=
+ Likewise fabs/negate preserve a NaN's payload but=0A=
+ subtraction doesn't. */=0A=
+=0A=
+double foo (double x)=0A=
+{=0A=
+ return 0.0 - x;=0A=
+}=0A=
+=0A=
+double bar (double y)=0A=
+{=0A=
+ return 0.0 - __builtin_fabs (y);=0A=
+}=0A=
+=0A=
+/* { dg-final { scan-tree-dump-times " \\- " 2 "optimized" } } */=0A=
diff --git a/gcc/testsuite/gcc.dg/pr126467-2.c =
b/gcc/testsuite/gcc.dg/pr126467-2.c=0A=
new file mode 100644=0A=
index 00000000000..28742553173=0A=
--- /dev/null=0A=
+++ b/gcc/testsuite/gcc.dg/pr126467-2.c=0A=
@@ -0,0 +1,15 @@=0A=
+/* PR tree-optimization/126467 */=0A=
+/* { dg-do compile } */=0A=
+/* { dg-options "-O2 -fno-signed-zeros -ffinite-math-only =
-fdump-tree-optimized" } */=0A=
+=0A=
+double foo (double x)=0A=
+{=0A=
+ return 0.0 - x;=0A=
+}=0A=
+=0A=
+double bar (double y)=0A=
+{=0A=
+ return 0.0 - __builtin_fabs (y);=0A=
+}=0A=
+=0A=
+/* { dg-final { scan-tree-dump-not " \\- " "optimized" } } */=0A=
diff --git a/gcc/testsuite/gcc.dg/pr96392.c =
b/gcc/testsuite/gcc.dg/pr96392.c=0A=
index fb7de217f96..82756907f3f 100644=0A=
--- a/gcc/testsuite/gcc.dg/pr96392.c=0A=
+++ b/gcc/testsuite/gcc.dg/pr96392.c=0A=
@@ -12,11 +12,6 @@ double sub0(int x)=0A=
return x - 0.0;=0A=
}=0A=
=0A=
-double negate(int x)=0A=
-{=0A=
- return 0.0 - x;=0A=
-}=0A=
-=0A=
double subtract(int x)=0A=
{=0A=
return (double)x - (double)x;=0A=
------=_NextPart_000_0032_01DD24B9.6E0A9580--