Bug 125431 - [14/15/16 Regression] Generated complex-arithmetic code includes FCMLA instructions even when -ffp-contract=off
Summary: [14/15/16 Regression] Generated complex-arithmetic code includes FCMLA instru...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 15.2.0
: P3 normal
Target Milestone: 14.5
Assignee: Tamar Christina
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2026-05-23 22:36 UTC by Rich Townsend
Modified: 2026-06-17 11:58 UTC (History)
3 users (show)

See Also:
Host:
Target: aarch64
Build:
Known to work:
Known to fail:
Last reconfirmed: 2026-06-02 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rich Townsend 2026-05-23 22:36:37 UTC
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.
Comment 1 Steve Kargl 2026-05-25 16:14:34 UTC
This looks like a target problem exposed by the Fortran front end.
I suspect none the usual Fortran contributors can help.
Comment 2 Richard Biener 2026-06-02 09:06:18 UTC
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?
Comment 3 Tamar Christina 2026-06-02 09:41:55 UTC
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.
Comment 4 GCC Commits 2026-06-03 08:42:56 UTC
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.
Comment 5 Tamar Christina 2026-06-03 08:50:36 UTC
Fixed in trunk so far, will backport on early friday morning.
Comment 6 GCC Commits 2026-06-05 09:58:48 UTC
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)
Comment 7 Tamar Christina 2026-06-05 10:00:19 UTC
Waiting for CI to finish for 14 and 16 and will push those too.
Comment 8 GCC Commits 2026-06-17 11:53:08 UTC
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)
Comment 9 GCC Commits 2026-06-17 11:57:19 UTC
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)
Comment 10 Tamar Christina 2026-06-17 11:58:53 UTC
Fixed on all branches. Thanks for the report!