I am working on some performance-critical DSP code destined to run on an ARM Cortex-M4. One particular section of the code (a sinc interpolation function) is dense with multiply-accumulate operations and I am trying to ensure that performance is as good as possible so we can clock the MCU slower and save power.
Now, I have inspected the code emitted by arm-none-gcc-eabi for my interpolation function and it was not performant enough, so I have unrolled and rewritten the inner loop in assembly to use a string of VFMA fused multiply-add instructions like so:
VFMA.F32 S8, S24, S16 VFMA.F32 S8, S25, S17 VFMA.F32 S8, S26, S18 VFMA.F32 S8, S27, S19 VFMA.F32 S8, S28, S20 VFMA.F32 S8, S29, S21 VFMA.F32 S8, S30, S22 VFMA.F32 S8, S31, S23
To my surprise, however, the Cortex-M4 Technical Reference Manual says something strange about the performance of the VFMA instruction. While properly scheduled VADD and VMUL operations each take a single clock cycle, the CM4 TRM says that VFMA takes three clock cycles! On that basis, one would conclude that the fastest unrolled loop should consist of interleaved VMUL and VADD instructions, rather than half as many VFMA instructions.
There has been some discussion online about this issue but information is sparse as well as inconsistent. Some say that VFMA is aimed at code size reduction rather than speed improvement and that 3 cycles is normal. Others report observing a 2-clock execution time in a long unrolled loop, contrary to the CM4 TRM. One copy of the TRM says that when multiple VFMA operations are executed sequentially, the results are forwarded and the execution time is only 1 clock cycle. Some say that many of the slower VFMA measurements posted online suffer from additional slowdown due to flash wait states or improper configuration of the MCU's prefetch engine.
Can anyone shed some light on what factors influence the timing of VFMA on the Cortex-M4?