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

Reply via email to