I'm writing bare-metal/no-std code targeting the Arm Cortex-R5 processor, which does not have a floating-point unit (FPU) [1].
When compiling code that uses floats, rustc/llvm generates code that contain instructions not available on that processor. I'm trying to understand if this is due to:
- wrong expectations on my side;
- a bug in the Rust compiler;
- a bug in LLVM.
For example the code:
fn add_s(a: f32, b: f32) -> f32 {
a + b
}
fn add_d(a: f64, b: f64) -> f64 {
a + b
}
Is compiled to the following assembly (godbolt link), using rustc
version 1.79.0 with flags --target armv7r-none-eabi -C opt-level=3 -C target-cpu=cortex-r5
.
add_s:
vmov s0, r1
vmov s2, r0
vadd.f32 s0, s2, s0
vmov r0, s0
bx lr
add_d:
vmov d0, r2, r3
vmov d1, r0, r1
vadd.f64 d0, d1, d0
vmov r0, r1, d0
bx lr
Note the vadd.f32
and vadd.f64
instructions, which are not available on Cortex-R5 and cause the bare-metal program to halt.
If I don't set the target CPU, codegen is fine.
rustc flags: --target armv7r-none-eabi -C opt-level=3
add_s:
push {r11, lr}
bl __aeabi_fadd
pop {r11, pc}
add_d:
push {r11, lr}
bl __aeabi_dadd
pop {r11, pc}
Now I have some questions about this behavior:
- Am I right in expecting the target
armv7r-none-eabi
to generate code without FPU instructions and that therefore should run on the Cortex-R5? [2] - If yes, why does specifying the target CPU causes illegal instructions to be generated?
- Is there a way to see what rustc and llvm features are enabled by passing
-C target-cpu=cortex-r5
? I searched through the rustc repo, but couldn't find it. - Is this a bug in either rustc or llvm?
Thank you for your help!
Edit: modified example code to show both single-precision (f32
) and double-precision (f64
) versions of the code and generated assembly.