From 91290664756ebcd429348aaeb102590026df515a Mon Sep 17 00:00:00 2001 From: Andy Lin Date: Tue, 13 Jan 2026 02:03:06 +0800 Subject: [PATCH] Add the unsafe variant of dcp functions to floating point library Resolves #2790 Signed-off-by: Andy Lin --- src/rp2_common/pico_double/CMakeLists.txt | 5 ++++ src/rp2_common/pico_double/double_aeabi_dcp.S | 27 +++++++++++++++++- src/rp2_common/pico_double/double_fma_dcp.S | 9 ++++++ .../pico_double/include/pico/double.h | 19 +++++++++++++ src/rp2_common/pico_float/CMakeLists.txt | 5 ++++ src/rp2_common/pico_float/float_aeabi_dcp.S | 28 ++++++++++++++++++- .../pico_float/include/pico/float.h | 18 ++++++++++++ .../custom_double_funcs_test.c | 13 +++++++++ .../pico_float_test/custom_float_funcs_test.c | 13 +++++++++ test/pico_float_test/m33.c | 9 ++++++ 10 files changed, 144 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/pico_double/CMakeLists.txt b/src/rp2_common/pico_double/CMakeLists.txt index 5fe456304..2ad48d3e3 100644 --- a/src/rp2_common/pico_double/CMakeLists.txt +++ b/src/rp2_common/pico_double/CMakeLists.txt @@ -39,6 +39,11 @@ if (NOT TARGET pico_double) ${CMAKE_CURRENT_LIST_DIR}/double_sci_m33.S ${CMAKE_CURRENT_LIST_DIR}/double_conv_m33.S ) + + # PICO_CMAKE_CONFIG: PICO_DOUBLE_USE_UNSAFE_DCP, Use unsafe variant as the default implemention for all wrapper functions, default=0, type=bool, group=pico_double + if(PICO_DOUBLE_USE_UNSAFE_DCP) + target_compile_definitions(pico_double_pico INTERFACE PICO_DOUBLE_USE_UNSAFE_DCP=1) + endif() endif() target_link_libraries(pico_double_pico INTERFACE pico_bootrom pico_double_headers hardware_divider) diff --git a/src/rp2_common/pico_double/double_aeabi_dcp.S b/src/rp2_common/pico_double/double_aeabi_dcp.S index 8e055648d..c5975fe1d 100644 --- a/src/rp2_common/pico_double/double_aeabi_dcp.S +++ b/src/rp2_common/pico_double/double_aeabi_dcp.S @@ -29,6 +29,11 @@ double_section WRAPPER_FUNC_NAME(\func) // ============== STATE SAVE AND RESTORE =============== +// PICO_CONFIG: PICO_DOUBLE_USE_UNSAFE_DCP, Use unsafe variant as the default implemention for all wrapper functions, default=0, type=bool, group=pico_double +#if 0 +#define PICO_DOUBLE_USE_UNSAFE_DCP 0 +#endif + .macro saving_func type func, opt_label1='-', opt_label2='-' // Note we are usually 32-bit aligned already at this point, as most of the // function bodies contain exactly two 16-bit instructions: bmi and bx lr. @@ -47,10 +52,30 @@ regular_func \opt_label1 .ifnc \opt_label2,'-' regular_func \opt_label2 .endif - // This is the actual entry point: + // Configurable entry point of wrapper functions. +.ifc \type,wrapper +regular_func \func\()_safe +#if !PICO_DOUBLE_USE_UNSAFE_DCP \type\()_func \func +#endif +.else +\type\()_func \func +.endif PCMP apsr_nzcv bmi 1b +#if PICO_DOUBLE_USE_UNSAFE_DCP +.ifc \type,wrapper +\type\()_func \func +.endif +#endif +regular_func \func\()_unsafe +.ifnc \opt_label1,'-' +regular_func \opt_label1\()_unsafe +.endif +.ifnc \opt_label2,'-' +regular_func \opt_label2\()_unsafe +.endif + // This is the actual entry point: 1: .endm diff --git a/src/rp2_common/pico_double/double_fma_dcp.S b/src/rp2_common/pico_double/double_fma_dcp.S index bb810d0fb..64562dd80 100644 --- a/src/rp2_common/pico_double/double_fma_dcp.S +++ b/src/rp2_common/pico_double/double_fma_dcp.S @@ -73,11 +73,18 @@ double_wrapper_section __dfma @ r0:r1 m @ r2:r3 n @ [r13,#0] a +regular_func fma_safe +#if !PICO_DOUBLE_USE_UNSAFE_DCP wrapper_func fma +#endif mov r12,sp @ save the SP PCMP apsr_nzcv @ test the engaged flag bmi 1b 1: +#if PICO_DOUBLE_USE_UNSAFE_DCP +wrapper_func fma +#endif +regular_func fma_unsafe push {r4-r8,r14} ldrd r4,r5,[r12,#0] @ fetch a using original SP ubfx r7,r1,#20,#11 @ r7=em @@ -597,6 +604,8 @@ regular_func mla mov r12,sp @ save the SP PCMP apsr_nzcv @ test the engaged flag bmi 1b +regular_func fma_fast_unsafe +regular_func mla_unsafe 1: push {r4,r5,r14} dcp_dmul_m r0,r1,r0,r1,r2,r3,r0,r1,r2,r3,r4,r5,r14 diff --git a/src/rp2_common/pico_double/include/pico/double.h b/src/rp2_common/pico_double/include/pico/double.h index 6805078fb..79890b3d8 100644 --- a/src/rp2_common/pico_double/include/pico/double.h +++ b/src/rp2_common/pico_double/include/pico/double.h @@ -162,6 +162,19 @@ uint32_t double2ufix(double f, int e); int64_t double2fix64(double f, int e); uint64_t double2ufix64(double f, int e); +#if PICO_RP2350 +int32_t double2int_unsafe(double f); +uint32_t double2uint_unsafe(double f); +int32_t double2fix_unsafe(double f, int e); +uint32_t double2ufix_unsafe(double f, int e); +int32_t double2fix_z_unsafe(double f, int e); +double int2double_unsafe(int32_t i); +double uint2double_unsafe(uint32_t i); +int32_t double2int_z_unsafe(double f); +int32_t double2uint_z_unsafe(double f); +uint32_t double2ufix_z_unsafe(double f, int e); +#endif + #endif double exp10(double x); @@ -173,6 +186,12 @@ double ddiv_fast(double n, double d); double sqrt_fast(double f); double fma_fast(double x, double y, double z); // this is not fused double mla(double x, double y, double z); // another name for fma_fast +#if !defined(__riscv) && LIB_PICO_DOUBLE_PICO +double ddiv_fast_unsafe(double n, double d); +double sqrt_fast_unsafe(double f); +double fma_fast_unsafe(double x, double y, double z); +double mla_unsafe(double x, double y, double z); +#endif #endif #endif diff --git a/src/rp2_common/pico_float/CMakeLists.txt b/src/rp2_common/pico_float/CMakeLists.txt index f634f094d..1ab10b53f 100644 --- a/src/rp2_common/pico_float/CMakeLists.txt +++ b/src/rp2_common/pico_float/CMakeLists.txt @@ -129,6 +129,11 @@ ${CMAKE_CURRENT_LIST_DIR}/float_sci_m33.S ) + # PICO_CMAKE_CONFIG: PICO_FLOAT_USE_UNSAFE_DCP, Use unsafe variant as the default implemention for all wrapper functions, default=0, type=bool, group=pico_float + if(PICO_FLOAT_USE_UNSAFE_DCP) + target_compile_definitions(pico_float_pico_dcp INTERFACE PICO_FLOAT_USE_UNSAFE_DCP=1) + endif() + # NOTE the main reason for using pico_float_pico_dcp is presumably that you # don't want to use VFP at all, so turn off compiler support, otherwise, it will inline usages target_compile_options(pico_float_pico_dcp INTERFACE -msoft-float) diff --git a/src/rp2_common/pico_float/float_aeabi_dcp.S b/src/rp2_common/pico_float/float_aeabi_dcp.S index de170d3ef..58ea4c18f 100644 --- a/src/rp2_common/pico_float/float_aeabi_dcp.S +++ b/src/rp2_common/pico_float/float_aeabi_dcp.S @@ -49,10 +49,31 @@ regular_func \opt_label1 .ifnc \opt_label2,'-' regular_func \opt_label2 .endif - // This is the actual entry point: + // For wrapper functions: export `_safe`, `_unsafe` and configurable ``. + // For regular functions: export fixed `` and `_unsafe`. +.ifc \type,wrapper +regular_func \func\()_safe +#if !PICO_FLOAT_USE_UNSAFE_DCP +\type\()_func \func +#endif +.else \type\()_func \func +.endif PCMP apsr_nzcv bmi 1b +#if PICO_FLOAT_USE_UNSAFE_DCP +.ifc \type,wrapper +\type\()_func \func +.endif +#endif +regular_func \func\()_unsafe +.ifnc \opt_label1,'-' +regular_func \opt_label1\()_unsafe +.endif +.ifnc \opt_label2,'-' +regular_func \opt_label2\()_unsafe +.endif + // This is the actual entry point: 1: .endm @@ -138,6 +159,11 @@ saving_func regular fclassify // ============== CONVERSION FUNCTIONS =============== +// PICO_CONFIG: PICO_FLOAT_USE_UNSAFE_DCP, Use unsafe variant as the default implemention for all wrapper functions, default=0, type=bool, group=pico_float +#if 0 +#define PICO_FLOAT_USE_UNSAFE_DCP 0 +#endif + float_wrapper_section __aeabi_f2d saving_func wrapper __aeabi_f2d float2double dcp_float2double_m r0,r1,r0 diff --git a/src/rp2_common/pico_float/include/pico/float.h b/src/rp2_common/pico_float/include/pico/float.h index 31bea4687..9d9361805 100644 --- a/src/rp2_common/pico_float/include/pico/float.h +++ b/src/rp2_common/pico_float/include/pico/float.h @@ -184,6 +184,19 @@ uint32_t float2ufix(float f, int e); int64_t float2fix64(float f, int e); uint64_t float2ufix64(float f, int e); +#if LIB_PICO_FLOAT_PICO_DCP +float int2float_unsafe(int32_t i); +float uint2float_unsafe(uint32_t i); +int32_t float2int_z_unsafe(float f); +int32_t float2uint_z_unsafe(float f); +int32_t float2fix_z_unsafe(float f, int e); +int32_t float2int_unsafe(float f); +uint32_t float2uint_unsafe(float f); +int32_t float2fix_unsafe(float f, int e); +uint32_t float2ufix_unsafe(float f, int e); +uint32_t float2ufix_z_unsafe(float f, int e); +#endif + #if LIB_PICO_FLOAT_PICO_VFP // a bit of a hack to inline VFP fixed point conversion when exponent is constant and in range 1-32 #define fix2float(m, e) __builtin_choose_expr(__builtin_constant_p(e), (e) >= 1 && (e) <= 32 ? _fix2float_inline(m, e) : fix2 ## float(m, e), fix2 ## float(m, e)) @@ -295,6 +308,11 @@ float powintf(float x, int y); #if !PICO_RP2040 || PICO_COMBINED_DOCS float fdiv_fast(float n, float d); float sqrtf_fast(float f); + +#if LIB_PICO_FLOAT_PICO_DCP +float fdiv_fast_unsafe(float n, float d); +float sqrtf_fast_unsafe(float f); +#endif #endif #endif diff --git a/test/pico_float_test/custom_double_funcs_test.c b/test/pico_float_test/custom_double_funcs_test.c index e8f291f4c..9d997a83c 100644 --- a/test/pico_float_test/custom_double_funcs_test.c +++ b/test/pico_float_test/custom_double_funcs_test.c @@ -44,6 +44,19 @@ static inline double double2ufix_12(int32_t m) { return double2ufix(m, 12); } #define uint642double(i) ({ uint64_t _i = i; pico_default_asm_volatile("" : "+r" (_i)); uint642 ## double(_i); }) #endif +#if 1 && PICO_DOUBLE_USE_UNSAFE_DCP && !defined(__riscv) && PICO_RP2350 +#define int2double int2double_unsafe +#define uint2double uint2double_unsafe +#define double2fix double2fix_unsafe +#define double2ufix double2ufix_unsafe +#define double2fix_z double2fix_z_unsafe +#define double2ufix_z double2ufix_z_unsafe +#define double2int double2int_unsafe +#define double2int_z double2int_z_unsafe +#define double2uint double2uint_unsafe +#define double2uint_z double2uint_z_unsafe +#endif + int test() { int rc = 0; #if LIB_PICO_DOUBLE_PICO diff --git a/test/pico_float_test/custom_float_funcs_test.c b/test/pico_float_test/custom_float_funcs_test.c index 570ca0543..f59cd1852 100644 --- a/test/pico_float_test/custom_float_funcs_test.c +++ b/test/pico_float_test/custom_float_funcs_test.c @@ -18,6 +18,19 @@ #define test_checki64(x, expected, msg) ({ if ((x) != (expected)) { printf(" %s: %lld != %lld\n", msg, (int64_t)(x), (int64_t)(expected)); stop(); } }) #define test_checku64(x, expected, msg) ({ if ((uint64_t)(x) != (uint64_t)(expected)) { printf(" %s: %llu != %llu\n", msg, (uint64_t)(x), (uint64_t)(expected)); stop(); } }) +#if PICO_FLOAT_USE_UNSAFE_DCP && PICO_RP2350 && !defined(__riscv) +#define int2float int2float_unsafe +#define uint2float uint2float_unsafe +#define float2int float2int_unsafe +#define float2int_z float2int_z_unsafe +#define float2uint float2uint_unsafe +#define float2uint_z float2uint_z_unsafe +#define float2fix float2fix_unsafe +#define float2fix_z float2fix_z_unsafe +#define float2ufix float2ufix_unsafe +#define float2ufix_z float2ufix_z_unsafe +#endif + #if !(LIB_PICO_FLOAT_COMPILER || defined(__riscv)) static inline float fix2float_8(int32_t m) { return fix2float(m, 8); } static inline float fix2float_12(int32_t m) { return fix2float(m, 12); } diff --git a/test/pico_float_test/m33.c b/test/pico_float_test/m33.c index e42e797aa..7f3e95d08 100644 --- a/test/pico_float_test/m33.c +++ b/test/pico_float_test/m33.c @@ -15,8 +15,17 @@ extern ui64 sqrt_fast(ui64); #define m33cf_dadd __aeabi_dadd #define m33cf_dsub __aeabi_dsub #define m33cf_dmul __aeabi_dmul + +#if LIB_PICO_DOUBLE_PICO && PICO_DOUBLE_USE_UNSAFE_DCP +extern ui64 ddiv_fast_unsafe(ui64, ui64); +extern ui64 sqrt_fast_unsafe(ui64); +#define m33cf_ddiv_fast ddiv_fast_unsafe +#define m33cf_dsqrt_fast sqrt_fast_unsafe +#else #define m33cf_ddiv_fast ddiv_fast #define m33cf_dsqrt_fast sqrt_fast +#endif + static void checkf(ui32 r,ui32 t) { static int n=0; if(r!=t) {