[gcc r15-11275] AVR: target/125752 - Add 64-bit fixed point <-> 64-bit double conversions.
Georg-Johann Lay
gjl@gcc.gnu.org
Fri Jun 12 10:04:31 GMT 2026
https://gcc.gnu.org/g:eda7622e5104c44c8a10cccc758752605431360f
commit r15-11275-geda7622e5104c44c8a10cccc758752605431360f
Author: Georg-Johann Lay <avr@gjlay.de>
Date: Thu Jun 11 19:35:09 2026 +0200
AVR: target/125752 - Add 64-bit fixed point <-> 64-bit double conversions.
PR target/125752
libgcc/config/avr/libf7/
* libf7-asm.sx (ufx64_to_d, d_to_fx64): New DEFUNs.
(__fractdadf, __fractudadf, __fracttadf, __fractutadf)
(__fractdqdf, __fractudqdf): New _DEFUNs.
* libf7-common.mk (F7_ASM_PARTS) Add: fx2D, D2fx,
dq2D, udq2D, da2D, uda2D, ta2D uta2D.
(F7F): Add d_to_fx64, ufx64_to_d, sfx64_to_d.
* libf7.c (d_to_ufx, d_to_sfx): New protos.
(__fractdfda, __fractdfuda, __fractdfta, __fractdfuta)
(__fractdfdq, __fractdfudq): New modules.
* t-libf7 (LIBF7_DF_CONV): Add fractdfda,
fractdfta, fractdfdq, fractdfuda, fractdfuta, fractdfudq.
* f7-renames.h: Rebuild.
gcc/testsuite/
* gcc.target/avr/torture/fx-to-double.c: New test.
(cherry picked from commit 2a397b762827221ea5ed99d73062ae93846fa213)
Diff:
---
.../gcc.target/avr/torture/fx-to-double.c | 88 +++++++++++++++
libgcc/config/avr/libf7/f7-renames.h | 3 +
libgcc/config/avr/libf7/libf7-asm.sx | 122 ++++++++++++++++++++-
libgcc/config/avr/libf7/libf7-common.mk | 8 +-
libgcc/config/avr/libf7/libf7.c | 52 +++++++++
libgcc/config/avr/libf7/t-libf7 | 2 +
6 files changed, 271 insertions(+), 4 deletions(-)
diff --git a/gcc/testsuite/gcc.target/avr/torture/fx-to-double.c b/gcc/testsuite/gcc.target/avr/torture/fx-to-double.c
new file mode 100644
index 000000000000..761a57a8d8a8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/fx-to-double.c
@@ -0,0 +1,88 @@
+/* { dg-do run { target { ! avr_tiny } } } */
+/* { dg-additional-options "-std=gnu99 -Wno-pedantic" } */
+
+typedef long double DD;
+
+typedef long long _Fract dq_t;
+typedef long long _Accum ta_t;
+typedef long _Accum da_t;
+typedef unsigned long long _Fract udq_t;
+typedef unsigned long long _Accum uta_t;
+typedef unsigned long _Accum uda_t;
+
+#define NI __attribute__((noipa))
+
+#define MK_CONV(T) \
+ NI DD T##2d (T##_t x) \
+ { \
+ __asm ("" : "+r" (x)); \
+ return (DD) x; \
+ } \
+ \
+ NI T##_t d2##T (DD x) \
+ { \
+ __asm ("" : "+r" (x)); \
+ return (T##_t) x; \
+ }
+
+
+MK_CONV (da)
+MK_CONV (ta)
+MK_CONV (dq)
+
+MK_CONV (uda)
+MK_CONV (uta)
+MK_CONV (udq)
+
+#define TEST(T) \
+ do { \
+ T##_t fx = d2##T (x); \
+ DD y = T##2d (fx); \
+ if (y != x) \
+ __builtin_exit (__LINE__); \
+ } while (0)
+
+
+NI void test_s (DD x)
+{
+ TEST (da);
+ TEST (ta);
+
+ if (x < 1.0L && x >= -1.0L)
+ TEST (dq);
+}
+
+
+NI void test_u (long double x)
+{
+ TEST (uda);
+ TEST (uta);
+
+ if (x < 1.0L)
+ TEST (udq);
+}
+
+void test (DD x)
+{
+ if (x >= 0)
+ test_u (x);
+
+ test_s (x);
+}
+
+int main (void)
+{
+ test (+0.0L);
+ test (-0.0L);
+
+ test (+1.0L);
+ test (-1.0L);
+
+ test (-0x0.cafe123p0);
+ test (+0x0.cafe123p0);
+
+ test (+0x1234.cafe123p0);
+ test (-0x1234.cafe123p0);
+
+ return 0;
+}
diff --git a/libgcc/config/avr/libf7/f7-renames.h b/libgcc/config/avr/libf7/f7-renames.h
index dc098517ada4..c9f654a032c8 100644
--- a/libgcc/config/avr/libf7/f7-renames.h
+++ b/libgcc/config/avr/libf7/f7-renames.h
@@ -222,6 +222,9 @@
#define f7_sqrt16_floor_asm __f7_sqrt16_floor_asm
#define f7_lshrdi3_asm __f7_lshrdi3_asm
#define f7_ashldi3_asm __f7_ashldi3_asm
+#define f7_d_to_fx64_asm __f7_d_to_fx64_asm
+#define f7_ufx64_to_d_asm __f7_ufx64_to_d_asm
+#define f7_sfx64_to_d_asm __f7_sfx64_to_d_asm
#define f7_class_D_asm __f7_class_D_asm
#define f7_call_ddd_asm __f7_call_ddd_asm
#define f7_call_xdd_asm __f7_call_xdd_asm
diff --git a/libgcc/config/avr/libf7/libf7-asm.sx b/libgcc/config/avr/libf7/libf7-asm.sx
index f390eda73855..d368433ddbdc 100644
--- a/libgcc/config/avr/libf7/libf7-asm.sx
+++ b/libgcc/config/avr/libf7/libf7-asm.sx
@@ -2308,8 +2308,85 @@ _ENDF __fractqqdf
#endif /* F7MOD_qq2D_ */
+#ifdef F7MOD_fx2D_
+;;; Convert an [un]signed 64-bit fixed point value R18[] to double.
+;;; double ufx64_to_d (ufx64_t R18, uint8_t fbit R30);
+;;; double sfx64_to_d (sfx64_t R18, uint8_t fbit R30);
+;;; FBIT accounts for the fractional bits of the fixed point type,
+;;; e.g. pass __DA_FBIT__ for long accum etc.
+DEFUN ufx64_to_d
+ push r30
+ XCALL __floatundidf
+ rjmp 1f
+
+LABEL sfx64_to_d
+ push r30
+ XCALL __floatdidf
+1: pop r30
+
+ ;; The MSB indicates a value of 0. Notice that at this point,
+ ;; we have a normal floating point number with a biased exponent
+ ;; that won't underflow below.
+ tst r25
+ breq 0f
+
+ ;; Subtract fbit from the double exponent. R30[] = fbit << 4.
+ swap r30
+ mov r31, r30
+ andi r30, lo8 (0x0ff0)
+ andi r31, hi8 (0x0ff0)
+ sub r24, r30
+ sbc r25, r31
+
+0: ret
+ENDF ufx64_to_d
+#endif /* F7MOD_fx2D_ */
+
+#ifdef F7MOD_da2D_
+_DEFUN __fractdadf
+ ldi r30, __DA_FBIT__
+ F7jmp sfx64_to_d
+_ENDF __fractdadf
+#endif /* F7MOD_da2D_ */
+
+#ifdef F7MOD_uda2D_
+_DEFUN __fractudadf
+ ldi r30, __UDA_FBIT__
+ F7jmp ufx64_to_d
+_ENDF __fractudadf
+#endif /* F7MOD_uda2D_ */
+
+#ifdef F7MOD_ta2D_
+_DEFUN __fracttadf
+ ldi r30, __TA_FBIT__
+ F7jmp sfx64_to_d
+_ENDF __fracttadf
+#endif /* F7MOD_ta2D_ */
+
+#ifdef F7MOD_uta2D_
+_DEFUN __fractutadf
+ ldi r30, __UTA_FBIT__
+ F7jmp ufx64_to_d
+_ENDF __fractutadf
+#endif /* F7MOD_uta2D_ */
+
+#ifdef F7MOD_dq2D_
+_DEFUN __fractdqdf
+ ldi r30, __DQ_FBIT__
+ F7jmp sfx64_to_d
+_ENDF __fractdqdf
+#endif /* F7MOD_dq2D_ */
+
+#ifdef F7MOD_udq2D_
+_DEFUN __fractudqdf
+ ldi r30, __UDQ_FBIT__
+ F7jmp ufx64_to_d
+_ENDF __fractudqdf
+#endif /* F7MOD_udq2D_ */
+
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Fixed-point -> double conversions.
+;;; Double -> fixed-point conversions.
#ifdef F7MOD_D2qq_
_DEFUN __fractdfqq
@@ -2389,6 +2466,49 @@ _ENDF __fractdfusa
#endif /* F7MOD_D2usa_ */
+#ifdef F7MOD_D2fx_
+;;; Convert double R18 to a 64-bit fixed point value.
+;;; R18 d_to_fx64 (double R18, int8_t fbit R16);
+;;; |FBIT| accounts for the extra fbits compared to [u]int64_t.
+;;; FBIT < 0 indicates a signed conversion.
+;;; FBIT > 0 indicates an unsigned conversion.
+DEFUN d_to_fx64
+ do_prologue_saves 4, F7_SIZEOF
+
+ ;; Y = FramePointer + 1
+ adiw Y, 1
+
+ ;; FP + 1 = (f7_t) arg
+ wmov r16, Y
+
+ ;; Convert double R18 to f7_t *R16.
+ XCALL F7_NAME (set_double_impl)
+
+ ;; Prepare for *R24 = ldexp (*R24, R22). ldexp() accounts for the
+ ;; fractional bits of the fixed point value, i.e. we have to <<= FBIT.
+ wmov r24, r16
+ ;; Zero-extend FBIT.
+ clr r23
+ ;; R16 has been clobbered. Fetch it from where prologue_saves put it.
+ ldd r22, Y + F7_SIZEOF + 3 ; Saved R16
+ tst r22
+ brmi 1f
+
+ ;; Positive FBIT indicates an unsigned conversion.
+ XCALL F7_NAME (Ildexp)
+ XCALL F7_NAME (get_u64)
+ rjmp 9f
+
+1: ;; Negative FBIT indicates a signed conversion.
+ neg r22 ; FBIT := |FBIT|
+ XCALL F7_NAME (Ildexp)
+ XCALL F7_NAME (get_s64)
+
+9: do_epilogue_restores 4, F7_SIZEOF
+ENDF d_to_fx64
+#endif /* F7MOD_D2fx_ */
+
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; [u]int32_t -> double conversions.
diff --git a/libgcc/config/avr/libf7/libf7-common.mk b/libgcc/config/avr/libf7/libf7-common.mk
index e2b47409ba80..4c3091f4f437 100644
--- a/libgcc/config/avr/libf7/libf7-common.mk
+++ b/libgcc/config/avr/libf7/libf7-common.mk
@@ -29,12 +29,14 @@ F7_ASM_PARTS += D_cmp D_eq D_ne D_ge D_gt D_le D_lt D_unord D_fminfmax
F7_ASM_PARTS += call_dd call_ddd
# Fixed-point -> double conversions
-F7_ASM_PARTS += qq2D uqq2D sq2D usq2D
-F7_ASM_PARTS += ha2D uha2D sa2D usa2D
+F7_ASM_PARTS += qq2D uqq2D sq2D usq2D dq2D udq2D
+F7_ASM_PARTS += ha2D uha2D sa2D usa2D da2D uda2D ta2D uta2D
+F7_ASM_PARTS += fx2D
# Double -> fixed-point conversions
F7_ASM_PARTS += D2qq D2uqq D2hq D2uhq
F7_ASM_PARTS += D2ha D2uha D2sa D2usa
+F7_ASM_PARTS += D2fx
# Integer -> double conversions
F7_ASM_PARTS += D_floatsidf D_floatunsidf
@@ -107,7 +109,7 @@ F7F_asm += set_u64 set_s64 addsub_mant_scaled mul_mant
F7F_asm += to_integer to_unsigned clr_mant_lsbs
F7F_asm += div sqrt_approx sqrt16_round sqrt16_floor
F7F_asm += lshrdi3 ashldi3
-
+F7F_asm += d_to_fx64 ufx64_to_d sfx64_to_d
F7F_asm += class_D
F7F_asm += call_ddd call_xdd call_ddx
diff --git a/libgcc/config/avr/libf7/libf7.c b/libgcc/config/avr/libf7/libf7.c
index df738b0d5d0e..d7ef43cd49ea 100644
--- a/libgcc/config/avr/libf7/libf7.c
+++ b/libgcc/config/avr/libf7/libf7.c
@@ -140,6 +140,58 @@ f7_double_t __floatdidf (int64_t x)
#endif // F7MOD_floatdidf_
+extern uint64_t d_to_ufx (f7_double_t, int8_t) F7ASM(f7_d_to_fx64_asm);
+extern int64_t d_to_sfx (f7_double_t, int8_t) F7ASM(f7_d_to_fx64_asm);
+
+#ifdef F7MOD_fractdfda_
+F7_WEAK
+int64_t __fractdfda (f7_double_t d)
+{
+ return d_to_sfx (d, -__DA_FBIT__);
+}
+#endif // F7MOD_fractdfda_
+
+#ifdef F7MOD_fractdfuda_
+F7_WEAK
+uint64_t __fractdfuda (f7_double_t d)
+{
+ return d_to_ufx (d, __UDA_FBIT__);
+}
+#endif // F7MOD_fractdfuda_
+
+#ifdef F7MOD_fractdfta_
+F7_WEAK
+int64_t __fractdfta (f7_double_t d)
+{
+ return d_to_sfx (d, -__TA_FBIT__);
+}
+#endif // F7MOD_fractdfta_
+
+#ifdef F7MOD_fractdfuta_
+F7_WEAK
+uint64_t __fractdfuta (f7_double_t d)
+{
+ return d_to_ufx (d, __UTA_FBIT__);
+}
+#endif // F7MOD_fractdfuta_
+
+#ifdef F7MOD_fractdfdq_
+F7_WEAK
+int64_t __fractdfdq (f7_double_t d)
+{
+ return d_to_sfx (d, -__DQ_FBIT__);
+}
+#endif // F7MOD_fractdfdq_
+
+#ifdef F7MOD_fractdfudq_
+F7_WEAK
+uint64_t __fractdfudq (f7_double_t d)
+{
+ return d_to_ufx (d, __UDQ_FBIT__);
+}
+#endif // F7MOD_fractdfudq_
+
+
#ifdef F7MOD_init_
f7_t* f7_init_impl (uint64_t mant, uint8_t flags, f7_t *cc, int16_t expo)
{
diff --git a/libgcc/config/avr/libf7/t-libf7 b/libgcc/config/avr/libf7/t-libf7
index 9ec70d84ae88..d087053526ed 100644
--- a/libgcc/config/avr/libf7/t-libf7
+++ b/libgcc/config/avr/libf7/t-libf7
@@ -9,6 +9,8 @@ F7_PREFIX = __f7_
include $(libf7)/libf7-common.mk
LIBF7_DF_CONV += floatundidf floatdidf # floatunsidf floatsidf
+LIBF7_DF_CONV += fractdfda fractdfta fractdfdq
+LIBF7_DF_CONV += fractdfuda fractdfuta fractdfudq
# Wrappers like f7_lt_impl for f7_lt etc. because the latter is inline.
LIBF7_DF_CMP += lt le gt ge ne eq unord
More information about the Gcc-cvs
mailing list