[gcc r17-2947] AArch64: block COMPLEX_MUL when honoring signed zeros [PR126589]
Tamar Christina via Gcc-cvs <[email protected]> Tue, 4 Aug 2026 14:26:22 +0000 (GMT)
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:30b4b8f2baf42c8842233a2d075c77a01eee4d29 commit r17-2947-g30b4b8f2baf42c8842233a2d075c77a01eee4d29 Author: Tamar Christina <[email protected]> Date: Tue Aug 4 15:25:54 2026 +0100 AArch64: block COMPLEX_MUL when honoring signed zeros [PR126589] as PR126589 points out on AArch64 we emulate COMPLEX_MUL using COMPLEX_FMA by seeding the accumulator with +0.0. However depending on the rounding/flushing behavior we can end up with the wrong sign on the zero result. There's no real performant way to fix this (though I wonder if a BSL to copy the sign bits would be faster) so this adds !HONOR_SIGNED_ZEROS as a requirement for AArch64's expanders for cmul. gcc/ChangeLog: PR target/126589 * config/aarch64/aarch64-simd.md (cmul<conj_op><mode>3): Require not honor signed zeros. * config/aarch64/aarch64-sve.md (cmul<conj_op><mode>3): Require not honor signed zeros. gcc/testsuite/ChangeLog: PR target/126589 * gcc.target/aarch64/sve/complex_mul_1.c: Add -fno-signed-zeros. * gfortran.target/aarch64/pr122408_1.f90: Likewise. * gcc.target/aarch64/pr126589.c: New test. * gcc.target/aarch64/sve/pr126589.c: New test. Diff: --- gcc/config/aarch64/aarch64-simd.md | 2 +- gcc/config/aarch64/aarch64-sve.md | 2 +- gcc/testsuite/gcc.target/aarch64/pr126589.c | 36 ++++++++++++++++++++++ .../gcc.target/aarch64/sve/complex_mul_1.c | 2 +- gcc/testsuite/gcc.target/aarch64/sve/pr126589.c | 36 ++++++++++++++++++++++ .../gfortran.target/aarch64/pr122408_1.f90 | 2 +- 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index 433f16052bf2..aa6c1fa07353 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -670,7 +670,7 @@ (unspec:VHSDF [(match_operand:VHSDF 1 "register_operand") (match_operand:VHSDF 2 "register_operand")] FCMUL_OP))] - "TARGET_COMPLEX && !BYTES_BIG_ENDIAN" + "TARGET_COMPLEX && !BYTES_BIG_ENDIAN && !HONOR_SIGNED_ZEROS (<MODE>mode)" { rtx tmp = force_reg (<MODE>mode, CONST0_RTX (<MODE>mode)); rtx res1 = gen_reg_rtx (<MODE>mode); diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 105b34eb8fa9..f665417dba41 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -8297,7 +8297,7 @@ [(match_operand:SVE_FULL_F 1 "register_operand") (match_operand:SVE_FULL_F 2 "register_operand")] FCMUL_OP))] - "TARGET_SVE" + "TARGET_SVE && !HONOR_SIGNED_ZEROS (<MODE>mode)" { rtx pred_reg = aarch64_ptrue_reg (<VPRED>mode); rtx gp_mode = gen_int_mode (SVE_RELAXED_GP, SImode); diff --git a/gcc/testsuite/gcc.target/aarch64/pr126589.c b/gcc/testsuite/gcc.target/aarch64/pr126589.c new file mode 100644 index 000000000000..cece07d07a77 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr126589.c @@ -0,0 +1,36 @@ +/* { dg-do run { target arm_v8_3a_complex_neon_hw } } */ +/* { dg-require-effective-target aarch64_little_endian } */ +/* { dg-options "-O3 -march=armv8.3-a" } */ + +#define N 64 +double a[N], b[N], c[N]; + +__attribute__((noipa)) void +mul (double *__restrict cc, double *__restrict aa, double *__restrict bb, int n) +{ + for (int i = 0; i < n; i += 2) + { + cc[i] = aa[i] * bb[i] - aa[i + 1] * bb[i + 1]; + cc[i + 1] = aa[i] * bb[i + 1] + aa[i + 1] * bb[i]; + } +} + +int +main (void) +{ + for (int i = 0; i < N; i += 2) + { + a[i] = -0.0; + a[i + 1] = 0.0; + b[i] = 1.0; + b[i + 1] = 1.0; + } + + mul (c, a, b, N); + + for (int i = 0; i < N; i += 2) + if (!__builtin_signbit (c[i])) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/complex_mul_1.c b/gcc/testsuite/gcc.target/aarch64/sve/complex_mul_1.c index d197e7d0d8e3..7398338f9fd6 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/complex_mul_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/complex_mul_1.c @@ -1,4 +1,4 @@ -/* { dg-options "-O2 -fgimple -fdump-tree-optimized" } */ +/* { dg-options "-O2 -fgimple -fdump-tree-optimized -fno-signed-zeros" } */ void __GIMPLE foo (__SVFloat64_t x, __SVFloat64_t y, __SVFloat64_t *res1, diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pr126589.c b/gcc/testsuite/gcc.target/aarch64/sve/pr126589.c new file mode 100644 index 000000000000..0612df53df5b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pr126589.c @@ -0,0 +1,36 @@ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-require-effective-target arm_v8_3a_complex_neon_hw } */ +/* { dg-options "-O3 -march=armv8.3-a+sve -mautovec-preference=sve-only" } */ + +#define N 64 +double a[N], b[N], c[N]; + +__attribute__((noipa)) void +mul (double *__restrict cc, double *__restrict aa, double *__restrict bb, int n) +{ + for (int i = 0; i < n; i += 2) + { + cc[i] = aa[i] * bb[i] - aa[i + 1] * bb[i + 1]; + cc[i + 1] = aa[i] * bb[i + 1] + aa[i + 1] * bb[i]; + } +} + +int +main (void) +{ + for (int i = 0; i < N; i += 2) + { + a[i] = -0.0; + a[i + 1] = 0.0; + b[i] = 1.0; + b[i + 1] = 1.0; + } + + mul (c, a, b, N); + + for (int i = 0; i < N; i += 2) + if (!__builtin_signbit (c[i])) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gfortran.target/aarch64/pr122408_1.f90 b/gcc/testsuite/gfortran.target/aarch64/pr122408_1.f90 index c1996b748699..b06950d1baae 100644 --- a/gcc/testsuite/gfortran.target/aarch64/pr122408_1.f90 +++ b/gcc/testsuite/gfortran.target/aarch64/pr122408_1.f90 @@ -1,5 +1,5 @@ ! { dg-do compile } -! { dg-additional-options "-O2 -march=armv8.3-a" } +! { dg-additional-options "-O2 -march=armv8.3-a -fno-signed-zeros" } subroutine c_add_ab(n, a, c, b) ! C += A * B use iso_fortran_env, only: real64