[patch 2/2]AArch64: block COMPLEX_MUL when honoring signed zeros [PR126589]
Tamar Christina <[email protected]> Tue, 4 Aug 2026 13:22:06 +0100
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
--zeFPP5DaFSpZI9e9
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
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.
Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
Pushed as obvious fix.
Thanks,
Tamar
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 --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index 433f16052bf200d9a8debf940306f40c1f86e480..aa6c1fa07353960f5bfe42582c481f7cbb5f1d5b 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -670,7 +670,7 @@ (define_expand "cmul<conj_op><mode>3"
(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 105b34eb8fa943fcad2230642706929987d4aedc..f665417dba417337e4bd4f6c517c7b5acaf2ed39 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -8297,7 +8297,7 @@ (define_expand "cmul<conj_op><mode>3"
[(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 0000000000000000000000000000000000000000..cece07d07a771b3f3c57d2521ac07686942ad321
--- /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 d197e7d0d8e3c64723f51c8a12e8dfab9a629f99..7398338f9fd6bd2bcb138e3e40783b9f0b397bcb 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 0000000000000000000000000000000000000000..0612df53df5bb942e0e5f523e45e56d63d7de30a
--- /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 c1996b748699ea9e8b10a49d774e8f3e7d8163fc..b06950d1baae7d8aca2e1c96c8e6e942781b71bd 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
--
--zeFPP5DaFSpZI9e9
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment; filename="rb20768.patch"
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index 433f16052bf200d9a8debf940306f40c1f86e480..aa6c1fa07353960f5bfe42582c481f7cbb5f1d5b 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -670,7 +670,7 @@ (define_expand "cmul<conj_op><mode>3"
(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 105b34eb8fa943fcad2230642706929987d4aedc..f665417dba417337e4bd4f6c517c7b5acaf2ed39 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -8297,7 +8297,7 @@ (define_expand "cmul<conj_op><mode>3"
[(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 0000000000000000000000000000000000000000..cece07d07a771b3f3c57d2521ac07686942ad321
--- /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 d197e7d0d8e3c64723f51c8a12e8dfab9a629f99..7398338f9fd6bd2bcb138e3e40783b9f0b397bcb 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 0000000000000000000000000000000000000000..0612df53df5bb942e0e5f523e45e56d63d7de30a
--- /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 c1996b748699ea9e8b10a49d774e8f3e7d8163fc..b06950d1baae7d8aca2e1c96c8e6e942781b71bd 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
--zeFPP5DaFSpZI9e9--