Working with gfortran 15.2 on Apple Silicon, I'm finding that complex arithmetic generates assembly with FCMLA instructions even when -ffp-contract=off. I'm not sure this is a gfortran issue per se, but I've encountered it in a Fortran context. Example code: --- subroutine foo(a,b,c) complex :: a(6,6) complex :: b(6,6) complex :: c(6,6) c = MATMUL(a, b) end subroutine foo --- Compiling this on godbolt.org (AARCH64 gfortran 15.2.0) with options "-O2 -ffp-contract=off -mcpu=apple-m1" leads to the following assembly: -- foo_: stp x29, x30, [sp, -32]! mov x29, sp stp x19, x20, [sp, 16] mov x20, x1 mov x19, x0 mov w1, 0 mov x0, x2 mov x2, 288 bl memset mov x2, x0 mov x1, x20 add x6, x20, 288 add x5, x19, 288 .L4: mov x3, x19 mov x4, x1 .L3: ldr d30, [x4] mov x0, 0 uzp1 v30.2d, v30.2d, v30.2d .L2: ldr q28, [x3, x0] movi v27.4s, 0 ldr q29, [x2, x0] fcmla v27.4s, v30.4s, v28.4s, #0 fcmla v27.4s, v30.4s, v28.4s, #90 fadd v27.4s, v27.4s, v29.4s str q27, [x2, x0] add x0, x0, 16 cmp x0, 48 bne .L2 add x3, x3, 48 add x4, x4, 8 cmp x3, x5 bne .L3 add x1, x1, 48 add x2, x2, 48 cmp x6, x1 bne .L4 ldp x19, x20, [sp, 16] ldp x29, x30, [sp], 32 ret -- The generated code also includes FCMLA instructions with -march=armv8.3-a, but not with armv8.2-a or earlier (I'm guessing this is because FCMLA was introduced with armv8.3). If I rewrite the code using real variables, then FMLA instructions are not generated with -ffp-contract=off (but they *are* without this flag, as expected). This behavior strikes me as inconsistent: -ffp-contract is respected for real arithmetic, but not for complex arithmetic. I don't know whether it's purposeful, but it does create ulp-level differences in calculation results, which isn't ideal.
This looks like a target problem exposed by the Fortran front end. I suspect none the usual Fortran contributors can help.
This looks vectorization related, but the vectorizer guards things properly with flag_fp_contract_mode FP_CONTRACT_FAST so I wonder if the frontend somehow overrides flag_fp_contract_mode Tamar, can you check?
Confirmed. The check is in the wrong place, it was added in the lane swapping code rather than just a general condition so it reliably catches complex multiply and accumulate but not complex multiply. Testing a patch.
The master branch has been updated by Tamar Christina <tnfchris@gcc.gnu.org>: https://gcc.gnu.org/g:074ed30c2382f163b74e98baa4c242a721c57519 commit r17-1250-g074ed30c2382f163b74e98baa4c242a721c57519 Author: Tamar Christina <tamar.christina@arm.com> Date: Wed Jun 3 09:42:15 2026 +0100 vect: gate COMPLEX_MUL on FP_CONTRACT_FAST [PR125431] The checks for FP_CONTRACT_FAST were in the wrong place for complex_mul. The location it was in would only block FMA but not MUL. It would also not really reject the forming of the FMA, it would just create an invalid collection of nodes which would fail analysis later on. However complex multiplication is also a contraction, since it's doing real = a*c - b*d imag = a*d + b*c This moves the checks up to earliest possible location and actually just returns and adds the missing check for FMS. gcc/ChangeLog: PR tree-optimization/125431 * tree-vect-slp-patterns.cc (complex_mul_pattern::matches, complex_fms_pattern::matches): Gate on FP contraction. gcc/testsuite/ChangeLog: PR tree-optimization/125431 * gfortran.dg/vect/pr125431.f90: New test.
Fixed in trunk so far, will backport on early friday morning.
The releases/gcc-15 branch has been updated by Tamar Christina <tnfchris@gcc.gnu.org>: https://gcc.gnu.org/g:56d14d7653e80e865b8e57592978510253bad522 commit r15-11261-g56d14d7653e80e865b8e57592978510253bad522 Author: Tamar Christina <tamar.christina@arm.com> Date: Wed Jun 3 09:42:15 2026 +0100 vect: gate COMPLEX_MUL on FP_CONTRACT_FAST [PR125431] The checks for FP_CONTRACT_FAST were in the wrong place for complex_mul. The location it was in would only block FMA but not MUL. It would also not really reject the forming of the FMA, it would just create an invalid collection of nodes which would fail analysis later on. However complex multiplication is also a contraction, since it's doing real = a*c - b*d imag = a*d + b*c This moves the checks up to earliest possible location and actually just returns and adds the missing check for FMS. gcc/ChangeLog: PR tree-optimization/125431 * tree-vect-slp-patterns.cc (complex_mul_pattern::matches, complex_fms_pattern::matches): Gate on FP contraction. gcc/testsuite/ChangeLog: PR tree-optimization/125431 * gfortran.dg/vect/pr125431.f90: New test. (cherry picked from commit 074ed30c2382f163b74e98baa4c242a721c57519)
Waiting for CI to finish for 14 and 16 and will push those too.
The releases/gcc-16 branch has been updated by Tamar Christina <tnfchris@gcc.gnu.org>: https://gcc.gnu.org/g:d5998d61eef27c98baa0307b2302e2475b9a3d64 commit r16-9125-gd5998d61eef27c98baa0307b2302e2475b9a3d64 Author: Tamar Christina <tamar.christina@arm.com> Date: Wed Jun 3 09:42:15 2026 +0100 vect: gate COMPLEX_MUL on FP_CONTRACT_FAST [PR125431] The checks for FP_CONTRACT_FAST were in the wrong place for complex_mul. The location it was in would only block FMA but not MUL. It would also not really reject the forming of the FMA, it would just create an invalid collection of nodes which would fail analysis later on. However complex multiplication is also a contraction, since it's doing real = a*c - b*d imag = a*d + b*c This moves the checks up to earliest possible location and actually just returns and adds the missing check for FMS. gcc/ChangeLog: PR tree-optimization/125431 * tree-vect-slp-patterns.cc (complex_mul_pattern::matches, complex_fms_pattern::matches): Gate on FP contraction. gcc/testsuite/ChangeLog: PR tree-optimization/125431 * gfortran.dg/vect/pr125431.f90: New test. (cherry picked from commit 074ed30c2382f163b74e98baa4c242a721c57519)
The releases/gcc-14 branch has been updated by Tamar Christina <tnfchris@gcc.gnu.org>: https://gcc.gnu.org/g:69d9846282dfced57c2289d420d95aa1e0d82c08 commit r14-12675-g69d9846282dfced57c2289d420d95aa1e0d82c08 Author: Tamar Christina <tamar.christina@arm.com> Date: Wed Jun 3 09:42:15 2026 +0100 vect: gate COMPLEX_MUL on FP_CONTRACT_FAST [PR125431] The checks for FP_CONTRACT_FAST were in the wrong place for complex_mul. The location it was in would only block FMA but not MUL. It would also not really reject the forming of the FMA, it would just create an invalid collection of nodes which would fail analysis later on. However complex multiplication is also a contraction, since it's doing real = a*c - b*d imag = a*d + b*c This moves the checks up to earliest possible location and actually just returns and adds the missing check for FMS. gcc/ChangeLog: PR tree-optimization/125431 * tree-vect-slp-patterns.cc (complex_mul_pattern::matches, complex_fms_pattern::matches): Gate on FP contraction. gcc/testsuite/ChangeLog: PR tree-optimization/125431 * gfortran.dg/vect/pr125431.f90: New test. (cherry picked from commit 074ed30c2382f163b74e98baa4c242a721c57519)
Fixed on all branches. Thanks for the report!