https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126589
Bug ID: 126589
Summary: [13/14/15/16/17 Regression] Complex-mul vectorisation
not honoring signed zeros
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: ktkachov at gcc dot gnu.org
CC: tnfchris at gcc dot gnu.org
Target Milestone: ---
/* Wrong code: gcc/config/aarch64/aarch64-simd.md:668, "cmul<conj_op><mode>3"
The expander seeds the two-instruction FCMLA chain with a literal +0.0
accumulator:
rtx tmp = force_reg (<MODE>mode, CONST0_RTX (<MODE>mode));
emit_insn (gen_aarch64_fcmla<rotsplit1><mode> (res1, tmp, op2, op1));
emit_insn (gen_aarch64_fcmla<rotsplit2><mode> (op0, res1, op2, op1));
so it computes re = fma (-ai, bi, fma (ar, br, +0.0)) instead of the
documented op0[i] = op1[i] * op2[i]. The added +0.0 destroys the sign of a
zero result: (-0.0) + (+0.0) is +0.0 in round-to-nearest. Pure contraction
preserves it, so this is not licensed by -ffp-contract=fast. The expander
condition is only "TARGET_COMPLEX && !BYTES_BIG_ENDIAN", with no
!flag_signed_zeros test, and the SLP matcher that produces IFN_COMPLEX_MUL
(complex_mul_pattern::matches, tree-vect-slp-patterns.cc:1044) gates only on
flag_fp_contract_mode == FP_CONTRACT_FAST, which is the default for
-std=gnu*. It never consults HONOR_SIGNED_ZEROS. So -ffast-math /
-fno-signed-zeros is NOT needed to hit this: plain -O2 is enough.
With a[i] = -0.0, a[i+1] = 0.0, b[i] = b[i+1] = 1.0:
scalar : (-0.0 * 1.0) - (0.0 * 1.0) = -0.0 + -0.0 = -0.0 (signbit set)
FCMLA : fma (-0.0, 1.0, +0.0) = +0.0, then +0.0 + -0.0 = +0.0
Advanced SIMD codegen at -O2 -march=armv8.3-a:
movi v28.4s, 0
fcmla v28.2d, v29.2d, v30.2d, #0
fcmla v28.2d, v29.2d, v30.2d, #90
SVE codegen at -O3 -march=armv8.2-a+sve -msve-vector-bits=256:
movi d31, #0
movprfx z28, z31
fcmla z28.d, p6/m, z29.d, z30.d, #0
fcmla z28.d, p6/m, z29.d, z30.d, #90
Fix: add !HONOR_SIGNED_ZEROS (TREE_TYPE (SLP_TREE_VECTYPE (*node))) to the
gate at tree-vect-slp-patterns.cc:1044, or seed the expanders with -0.0
instead of +0.0. Only cmul/cmul_conj are affected. */
#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;
}
Aborts at -O3 -march=armv8.3-a on aarch64