https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124820
--- Comment #5 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Jeff Law <[email protected]>: https://gcc.gnu.org/g:2b6a76131e10592fca49006aea61844ee4894d89 commit r17-5664-g2b6a76131e10592fca49006aea61844ee4894d89 Author: Merlin Warner-Huish <[email protected]> Date: Wed Oct 28 07:17:05 2026 -0600 [PATCH] match.pd: Don't fold negated FMAs when honoring signed zeros [PR124820] The negated FMA folds in match.pd, such as -fma (a, b, c) -> fnms (a, b, c), give the wrong sign when a * b + c is exactly zero. For example, -fma (1.0, 1.0, -1.0) should be -0.0, since the fma rounds to +0.0 and is then negated, but fnms (1.0, 1.0, -1.0) computes -1.0 + 1.0, which rounds to +0.0. PR116891 already disabled these folds for -frounding-math. With the default rounding mode the sign of an exact zero is the only thing that can differ, so they are also only valid when signed zeros don't matter. This patch adds a !HONOR_SIGNED_ZEROS check to all four folds and to their IFN_COND_* versions. With -fno-signed-zeros the folds still apply. --- Bootstrapped and regression tested on x86_64-pc-linux-gnu. The only new failures were the scan-assembler counts in the gcc.target/i386 fma_* and l_fma_* tests, which expected the old folds; I added -fno-signed-zeros to those tests, and they now pass. The new tests pass at all torture options. I have only tested on x86_64. Other targets' negated-FMA tests may need the same -fno-signed-zeros change. Thanks to Kyrill Tkachov for the testcase in PR126461. PR middle-end/124820 gcc/ChangeLog: * match.pd ((negate (fmas@3 @0 @1 @2)) -> (IFN_FNMS @0 @1 @2)): Only enable for !HONOR_SIGNED_ZEROS. ((negate (IFN_FMS@3 @0 @1 @2)) -> (IFN_FNMA @0 @1 @2)): Likewise. ((negate (IFN_FNMA@3 @0 @1 @2)) -> (IFN_FMS @0 @1 @2)): Likewise. ((negate (IFN_FNMS@3 @0 @1 @2)) -> (IFN_FMA @0 @1 @2)): Likewise. ((negate (fmas@3 @4 @0 @1 @2 @5)) -> (IFN_COND_FNMS @4 @0 @1 @2 (negate @5))): Likewise. ((negate (IFN_COND_FMS@3 @4 @0 @1 @2 @5)) -> (IFN_COND_FNMA @4 @0 @1 @2 (negate @5))): Likewise. ((negate (IFN_COND_FNMA@3 @4 @0 @1 @2 @5)) -> (IFN_COND_FMS @4 @0 @1 @2 (negate @5))): Likewise. ((negate (IFN_COND_FNMS@3 @4 @0 @1 @2 @5)) -> (IFN_COND_FMA @4 @0 @1 @2 (negate @5))): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/pr124820.c: New test. * gcc.target/i386/fma-pr124820.c: New test. * gcc.target/i386/fma_double_1.c: Add -fno-signed-zeros. * gcc.target/i386/fma_double_2.c: Likewise. * gcc.target/i386/fma_double_3.c: Likewise. * gcc.target/i386/fma_double_4.c: Likewise. * gcc.target/i386/fma_double_5.c: Likewise. * gcc.target/i386/fma_double_6.c: Likewise. * gcc.target/i386/fma_float_1.c: Likewise. * gcc.target/i386/fma_float_2.c: Likewise. * gcc.target/i386/fma_float_3.c: Likewise. * gcc.target/i386/fma_float_4.c: Likewise. * gcc.target/i386/fma_float_5.c: Likewise. * gcc.target/i386/fma_float_6.c: Likewise. * gcc.target/i386/l_fma_double_1.c: Likewise. * gcc.target/i386/l_fma_double_2.c: Likewise. * gcc.target/i386/l_fma_double_3.c: Likewise. * gcc.target/i386/l_fma_double_4.c: Likewise. * gcc.target/i386/l_fma_double_5.c: Likewise. * gcc.target/i386/l_fma_double_6.c: Likewise. * gcc.target/i386/l_fma_float_1.c: Likewise. * gcc.target/i386/l_fma_float_2.c: Likewise. * gcc.target/i386/l_fma_float_3.c: Likewise. * gcc.target/i386/l_fma_float_4.c: Likewise. * gcc.target/i386/l_fma_float_5.c: Likewise. * gcc.target/i386/l_fma_float_6.c: Likewise.
