We have found that GCC >= 9 uses ARM VFP registers to store local function
variables instead of storing them on stack. It looks like a smart idea, because accessing
the VFP register is faster than accessing a stack, but there is one serious
problem.
The compiler can produce code like this for ANY more complex function with a lot of local variables, including functions which doesn’t use float point in sources:
stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
vpush {d8}
… do something
vmov s16, r3 ; temporarily store a local varible to a VFP register
… do something (*)
vmov r1, s16 ; restore the local variable from a temporary VFP register
… do something
vpop {d8}
ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
Problem is, that only some processes have a flag to save/restore FPU/VFP context (vPortEnableVFP function on ARM_CM4F or vPortTaskUsesFPU on ARM_CR5 and ARM_CA9)
When FreeRTOS saves/restores another process context on (*) location, and current process haven’t FPU/VFP enabled, then local function variable will be destroyed.
One possible work around is to enable FPU/VFP for ALL processes regardless whether they uses a float point unit. But it has a significant impact to used stack and context switching time.
Another workaround is to pass -mgeneral-regs-only option to the compiler, but it is not compatible with code, which regularly uses floating point operations.