我正在使用带有FPU的stm32f4芯片(cortex-m4)和
sqrt(9.7 * 9.7)返回94.17 ..
我正在使用arm-none-eabi-gcc编译器,并且在编译时不会出现任何错误。
我的makefile非常长,因为同一个文件用于stm32f4和sam4芯片。我甚至不知道要发布的相关部分。任何帮助表示赞赏。
编辑:来自makefile的一些标志配置
C_FLAGS = -mcpu=cortex-m4 -mthumb
C_FLAGS += -std=gnu89 -g -ggdb3 -fverbose-asm
C_FLAGS += --param max-inline-insns-single=500
C_FLAGS += -fsingle-precision-constant
C_FLAGS += -mfpu=fpv4-sp-d16
C_FLAGS += -mfloat-abi=hard
C_WARNINGS = -Wall
C_WARNINGS += -Wdouble-promotion
这是我的确切代码:
float x, y, z, mag;
x = ((float) (((int32_t) x_adc) + 0x8000)) * scale - offset;
y = ((float) (((int32_t) y_adc) + 0x8000)) * scale - offset;
z = ((float) (((int32_t) z_adc) + 0x8000)) * scale - offset;
mag = sqrt(x*x + y*y + z*z);
DEBUG("XYZ = %.2f, %.2f, %.2f = %.2f\n", x, y, z, mag );
DEBUG宏打印到usb_cdc接口和LCD屏幕上的调试日志。此外,我一直在覆盖Wdouble-promotion,现在我在DEBUG线上收到了一个双重促销警告(用__VA_ARGS__
调用snprintf)。我认为这不相关。
我将优化级别更改为0(仍然与sqrt得到相同的结果),这是.lss:
mag = sqrt(x*x + y*y + z*z);
8019a36: ed97 7a05 vldr s14, [r7, #20]
8019a3a: edd7 7a05 vldr s15, [r7, #20]
8019a3e: ee27 7a27 vmul.f32 s14, s14, s15
8019a42: edd7 6a04 vldr s13, [r7, #16]
8019a46: edd7 7a04 vldr s15, [r7, #16]
8019a4a: ee66 7aa7 vmul.f32 s15, s13, s15
8019a4e: ee37 7a27 vadd.f32 s14, s14, s15
8019a52: edd7 6a03 vldr s13, [r7, #12]
8019a56: edd7 7a03 vldr s15, [r7, #12]
8019a5a: ee66 7aa7 vmul.f32 s15, s13, s15
8019a5e: ee77 7a27 vadd.f32 s15, s14, s15
8019a62: ee17 0a90 vmov r0, s15
8019a66: f7e6 fcf3 bl 8000450 <__aeabi_f2d>
8019a6a: 4602 mov r2, r0
8019a6c: 460b mov r3, r1
8019a6e: ec43 2b10 vmov d0, r2, r3
8019a72: f007 fe9f bl 80217b4 <sqrt>
8019a76: ec53 2b10 vmov r2, r3, d0
8019a7a: 4610 mov r0, r2
8019a7c: 4619 mov r1, r3
8019a7e: f7e6 fffd bl 8000a7c <__aeabi_d2f>
8019a82: 4603 mov r3, r0
8019a84: 60bb str r3, [r7, #8]
if( 1 ) {
DEBUG("XYZ = %.2f, %.2f, %.2f = %.2f\n", x, y, z, mag );
8019a86: 6978 ldr r0, [r7, #20]
8019a88: f7e6 fce2 bl 8000450 <__aeabi_f2d>
8019a8c: 4682 mov sl, r0
8019a8e: 468b mov fp, r1
8019a90: 6938 ldr r0, [r7, #16]
8019a92: f7e6 fcdd bl 8000450 <__aeabi_f2d>
8019a96: 4680 mov r8, r0
8019a98: 4689 mov r9, r1
8019a9a: 68f8 ldr r0, [r7, #12]
8019a9c: f7e6 fcd8 bl 8000450 <__aeabi_f2d>
8019aa0: 4604 mov r4, r0
8019aa2: 460d mov r5, r1
8019aa4: 68b8 ldr r0, [r7, #8]
8019aa6: f7e6 fcd3 bl 8000450 <__aeabi_f2d>
8019aaa: 4602 mov r2, r0
8019aac: 460b mov r3, r1
8019aae: e9cd ab00 strd sl, fp, [sp]
8019ab2: e9cd 8902 strd r8, r9, [sp, #8]
8019ab6: e9cd 4504 strd r4, r5, [sp, #16]
8019aba: e9cd 2306 strd r2, r3, [sp, #24]
8019abe: f243 707c movw r0, #14204 ; 0x377c
8019ac2: f6c0 0002 movt r0, #2050 ; 0x802
8019ac6: f240 4176 movw r1, #1142 ; 0x476
8019aca: f643 0218 movw r2, #14360 ; 0x3818
8019ace: f6c0 0202 movt r2, #2050 ; 0x802
8019ad2: f643 430c movw r3, #15372 ; 0x3c0c
8019ad6: f6c0 0302 movt r3, #2050 ; 0x802
8019ada: f7ed fee9 bl 80078b0 <debug_log>
这是-O2
x = ((float) (((int32_t) x_adc) + 0x8000)) * scale - offset;
8010c3e: eeb0 9a48 vmov.f32 s18, s16
8010c42: ee10 9aa9 vnmls.f32 s18, s1, s19
y = ((float) (((int32_t) y_adc) + 0x8000)) * scale - offset;
z = ((float) (((int32_t) z_adc) + 0x8000)) * scale - offset;
8010c46: eef8 1ac1 vcvt.f32.s32 s3, s2
mag = sqrt(x*x + y*y + z*z);
8010c4a: ee28 2aa8 vmul.f32 s4, s17, s17
y_adc = ((int16_t) (buffer[2] & 0xff)) + (((int16_t) (buffer[3] & 0xff))<<8);
z_adc = ((int16_t) (buffer[4] & 0xff)) + (((int16_t) (buffer[5] & 0xff))<<8);
x = ((float) (((int32_t) x_adc) + 0x8000)) * scale - offset;
y = ((float) (((int32_t) y_adc) + 0x8000)) * scale - offset;
z = ((float) (((int32_t) z_adc) + 0x8000)) * scale - offset;
8010c4e: ee11 8aa9 vnmls.f32 s16, s3, s19
mag = sqrt(x*x + y*y + z*z);
8010c52: ee09 2a09 vmla.f32 s4, s18, s18
8010c56: ee08 2a08 vmla.f32 s4, s16, s16
8010c5a: ee12 0a10 vmov r0, s4
8010c5e: f7ef fbf7 bl 8000450 <__aeabi_f2d>
8010c62: ec41 0b10 vmov d0, r0, r1
8010c66: f007 f8f9 bl 8017e5c <sqrt>
if( 1 ) {
DEBUG("XYZ = %.2f, %.2f, %.2f = %.2f\n", x, y, z, mag );
8010c6a: ee19 0a10 vmov r0, s18
z_adc = ((int16_t) (buffer[4] & 0xff)) + (((int16_t) (buffer[5] & 0xff))<<8);
x = ((float) (((int32_t) x_adc) + 0x8000)) * scale - offset;
y = ((float) (((int32_t) y_adc) + 0x8000)) * scale - offset;
z = ((float) (((int32_t) z_adc) + 0x8000)) * scale - offset;
mag = sqrt(x*x + y*y + z*z);
8010c6e: ec55 4b10 vmov r4, r5, d0
if( 1 ) {
DEBUG("XYZ = %.2f, %.2f, %.2f = %.2f\n", x, y, z, mag );
8010c72: f7ef fbed bl 8000450 <__aeabi_f2d>
8010c76: e9cd 0100 strd r0, r1, [sp]
8010c7a: ee18 0a90 vmov r0, s17
8010c7e: f7ef fbe7 bl 8000450 <__aeabi_f2d>
8010c82: e9cd 0102 strd r0, r1, [sp, #8]
8010c86: ee18 0a10 vmov r0, s16
8010c8a: f7ef fbe1 bl 8000450 <__aeabi_f2d>
8010c8e: e9cd 0104 strd r0, r1, [sp, #16]
z_adc = ((int16_t) (buffer[4] & 0xff)) + (((int16_t) (buffer[5] & 0xff))<<8);
x = ((float) (((int32_t) x_adc) + 0x8000)) * scale - offset;
y = ((float) (((int32_t) y_adc) + 0x8000)) * scale - offset;
z = ((float) (((int32_t) z_adc) + 0x8000)) * scale - offset;
mag = sqrt(x*x + y*y + z*z);
8010c92: 4629 mov r1, r5
8010c94: 4620 mov r0, r4
8010c96: f7ef fef1 bl 8000a7c <__aeabi_d2f>
if( 1 ) {
DEBUG("XYZ = %.2f, %.2f, %.2f = %.2f\n", x, y, z, mag );
8010c9a: f7ef fbd9 bl 8000450 <__aeabi_f2d>
8010c9e: 4a0e ldr r2, [pc, #56] ; (8010cd8 <LIS331DLH_ReadAc+0x134>)
8010ca0: 4b0e ldr r3, [pc, #56] ; (8010cdc <LIS331DLH_ReadAc+0x138>)
8010ca2: e9cd 0106 strd r0, r1, [sp, #24]
8010ca6: 4808 ldr r0, [pc, #32] ; (8010cc8 <LIS331DLH_ReadAc+0x124>)
8010ca8: f240 4176 movw r1, #1142 ; 0x476
8010cac: f7f4 fb76 bl 800539c <debug_log>
8010cb0: e78b b.n 8010bca <LIS331DLH_ReadAc+0x26>
答案 0 :(得分:1)
这一切都取决于你如何使用它。你需要粘贴更多的信息/代码。一个简单的测试用例,这个简单测试用例的反汇编,你如何确定结果等等。
#include <math.h>
double fun ( void )
{
return(sqrt(9.7*9.7));
}
如上所述,数学库没有理由它是编译时计算(在主机/开发机器上)。
00000000 <fun>:
0: 4902 ldr r1, [pc, #8] ; (c <fun+0xc>)
2: 4801 ldr r0, [pc, #4] ; (8 <fun+0x8>)
4: 4770 bx lr
6: 46c0 nop ; (mov r8, r8)
8: 66666666 strbtvs r6, [r6], -r6, ror #12
c: 40236666 eormi r6, r3, r6, ror #12
为x86构建以显示arm的构建不会给出不同的预先计算的答案。
0000000000000000 <fun>:
0: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 # 8 <fun+0x8>
7: 00
8: c3 retq
0000000000000000 <.LC0>:
0: 66 data16
1: 66 data16
2: 66 data16
3: 66 data16
4: 66 data16
5: 66 data16
6: 23 .byte 0x23
7: 40 rex
切换到单精度
#include <math.h>
float fun ( void )
{
return(sqrtf(9.7F*9.7F));
}
float fun2 ( void )
{
return(9.7F);
}
我们得到单精度编译时计算答案
00000000 <fun>:
0: 4800 ldr r0, [pc, #0] ; (4 <fun+0x4>)
2: 4770 bx lr
4: 411b3333 tstmi fp, r3, lsr r3
00000008 <fun2>:
8: 4800 ldr r0, [pc, #0] ; (c <fun2+0x4>)
a: 4770 bx lr
c: 411b3333 tstmi fp, r3, lsr r3
使用clang / llvm而不是gcc:
fun:
ldr.n r0, .LCPI0_0
bx lr
.align 2
.LCPI0_0:
.long 1092301619 @ 0x411b3333
fun2:
ldr.n r0, .LCPI1_0
bx lr
.align 2
.LCPI1_0:
.long 1092301619 @ 0x411b3333
所以你需要重复一遍,看看你是否正在调用数学函数,如果是这样,他们提供了什么样的sqrt,他们实际上是否链接了正确的东西,那么我只是将结果打印成十六进制。然后调试另一半,是否采用正确的9.7F值并根据您的打印功能生成正确的ascii?
如何将(单精度)float转换为你问的十六进制?
.thumb_func
.globl dummy
dummy:
bx lr
验证编译器在进出的路上使用r0:
unsigned int fun3 ( void )
{
return(dummy(9.7F));
}
00000010 <fun3>:
10: b508 push {r3, lr}
12: 4803 ldr r0, [pc, #12] ; (20 <fun3+0x10>)
14: f7ff fffe bl 0 <dummy>
18: bc08 pop {r3}
1a: bc02 pop {r1}
1c: 4708 bx r1
1e: 46c0 nop ; (mov r8, r8)
20: 411b3333 tstmi fp, r3, lsr r3
通过简单地返回r0中的位作为浮点而不改变,这些位的定义无论如何都是编译器或程序员的想象,比特只是受到任何解释的位。