ARM Cortex M 的 gcc 不支持 FPU?
No FPU support with gcc for ARM Cortex M?
我使用 gcc-arm-none-eabi-10-2020-q4-major
编译的一个众所周知的基准测试有以下功能:
#include <unistd.h>
double b[1000], c[1000];
void tuned_STREAM_Scale(double scalar)
{
ssize_t j;
for (j = 0; j < 1000; j++)
b[j] = scalar* c[j];
}
我正在使用以下编译器选项:
arm-none-eabi-gcc -O3 -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 -c test.c
但是,如果我检查编译后的代码,编译器似乎无法使用基本的 FPU 乘法指令,而只是使用 libgcc
中的 __aeabi_dmul
函数(但是我们可以看到 FPU使用 vmov
):
00000000 <tuned_STREAM_Scale>:
0: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr}
4: 4c08 ldr r4, [pc, #32] ; (28 <tuned_STREAM_Scale+0x28>)
6: 4d09 ldr r5, [pc, #36] ; (2c <tuned_STREAM_Scale+0x2c>)
8: f504 58fa add.w r8, r4, #8000 ; 0x1f40
c: ec57 6b10 vmov r6, r7, d0
10: e8f4 0102 ldrd r0, r1, [r4], #8
14: 4632 mov r2, r6
16: 463b mov r3, r7
18: f7ff fffe bl 0 <__aeabi_dmul>
1c: 4544 cmp r4, r8
1e: e8e5 0102 strd r0, r1, [r5], #8
22: d1f5 bne.n 10 <tuned_STREAM_Scale+0x10>
24: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc}
如果我和其他编译器比较的话,代码效率是无与伦比的:
00000000 <tuned_STREAM_Scale>:
0: 4808 ldr r0, [pc, #32] ; (24 <tuned_STREAM_Scale+0x24>)
2: b580 push {r7, lr}
4: 4b06 ldr r3, [pc, #24] ; (20 <tuned_STREAM_Scale+0x20>)
6: 27c8 movs r7, #200 ; 0xc8
8: c806 ldmia r0!, {r1, r2}
a: ec42 1b11 vmov d1, r1, r2
e: ee20 1b01 vmul.f64 d1, d0, d1
12: 1e7f subs r7, r7, #1
14: ec52 1b11 vmov r1, r2, d1
18: c306 stmia r3!, {r1, r2}
1a: d1f5 bne.n 8 <tuned_STREAM_Scale+0x8>
1c: bd80 pop {r7, pc}
如果我根据 CPU 或 FPU 选项在 gcc 包中检查各种 libgcc
目标文件,我在 __aeabi_dmul
或任何其他函数中找不到任何 FPU 指令。
我觉得很奇怪 gcc 不能使用基本的 FPU 乘法,而且我在任何文档或 README 中都找不到这个限制,所以我想知道我是否做错了什么。我已经检查了旧的 gcc 版本,但我仍然有这个问题。是因为 gcc 还是来自 ARM 的编译二进制文件?
线索在您已经发布的编译器选项中:
-mfpu=fpv5-sp-d16
"sp" 表示单精度。
您告诉它不要生成硬件双指令,这对于大多数 Cortex-M7 处理器来说是正确的,因为它们无法执行。如果您有 M7 可以,那么您需要设置正确的 fpu 参数。
我使用 gcc-arm-none-eabi-10-2020-q4-major
编译的一个众所周知的基准测试有以下功能:
#include <unistd.h>
double b[1000], c[1000];
void tuned_STREAM_Scale(double scalar)
{
ssize_t j;
for (j = 0; j < 1000; j++)
b[j] = scalar* c[j];
}
我正在使用以下编译器选项:
arm-none-eabi-gcc -O3 -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 -c test.c
但是,如果我检查编译后的代码,编译器似乎无法使用基本的 FPU 乘法指令,而只是使用 libgcc
中的 __aeabi_dmul
函数(但是我们可以看到 FPU使用 vmov
):
00000000 <tuned_STREAM_Scale>:
0: e92d 41f0 stmdb sp!, {r4, r5, r6, r7, r8, lr}
4: 4c08 ldr r4, [pc, #32] ; (28 <tuned_STREAM_Scale+0x28>)
6: 4d09 ldr r5, [pc, #36] ; (2c <tuned_STREAM_Scale+0x2c>)
8: f504 58fa add.w r8, r4, #8000 ; 0x1f40
c: ec57 6b10 vmov r6, r7, d0
10: e8f4 0102 ldrd r0, r1, [r4], #8
14: 4632 mov r2, r6
16: 463b mov r3, r7
18: f7ff fffe bl 0 <__aeabi_dmul>
1c: 4544 cmp r4, r8
1e: e8e5 0102 strd r0, r1, [r5], #8
22: d1f5 bne.n 10 <tuned_STREAM_Scale+0x10>
24: e8bd 81f0 ldmia.w sp!, {r4, r5, r6, r7, r8, pc}
如果我和其他编译器比较的话,代码效率是无与伦比的:
00000000 <tuned_STREAM_Scale>:
0: 4808 ldr r0, [pc, #32] ; (24 <tuned_STREAM_Scale+0x24>)
2: b580 push {r7, lr}
4: 4b06 ldr r3, [pc, #24] ; (20 <tuned_STREAM_Scale+0x20>)
6: 27c8 movs r7, #200 ; 0xc8
8: c806 ldmia r0!, {r1, r2}
a: ec42 1b11 vmov d1, r1, r2
e: ee20 1b01 vmul.f64 d1, d0, d1
12: 1e7f subs r7, r7, #1
14: ec52 1b11 vmov r1, r2, d1
18: c306 stmia r3!, {r1, r2}
1a: d1f5 bne.n 8 <tuned_STREAM_Scale+0x8>
1c: bd80 pop {r7, pc}
如果我根据 CPU 或 FPU 选项在 gcc 包中检查各种 libgcc
目标文件,我在 __aeabi_dmul
或任何其他函数中找不到任何 FPU 指令。
我觉得很奇怪 gcc 不能使用基本的 FPU 乘法,而且我在任何文档或 README 中都找不到这个限制,所以我想知道我是否做错了什么。我已经检查了旧的 gcc 版本,但我仍然有这个问题。是因为 gcc 还是来自 ARM 的编译二进制文件?
线索在您已经发布的编译器选项中:
-mfpu=fpv5-sp-d16
"sp" 表示单精度。
您告诉它不要生成硬件双指令,这对于大多数 Cortex-M7 处理器来说是正确的,因为它们无法执行。如果您有 M7 可以,那么您需要设置正确的 fpu 参数。