diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2024-05-08 17:56:05 +0200 |
---|---|---|
committer | Georg-Johann Lay <avr@gjlay.de> | 2024-05-08 19:04:06 +0200 |
commit | de4eea7d7ea86e54843507c68d6672eca9d8c7bb (patch) | |
tree | 7d238cb292c1bad7eefff0135c4c523bcbda8bfb /libgcc/config/avr | |
parent | 2f00e6caca1a14dfe26e94f608e9d79a787ebe08 (diff) | |
download | gcc-de4eea7d7ea86e54843507c68d6672eca9d8c7bb.zip gcc-de4eea7d7ea86e54843507c68d6672eca9d8c7bb.tar.gz gcc-de4eea7d7ea86e54843507c68d6672eca9d8c7bb.tar.bz2 |
AVR: target/114981 - Support __builtin_powi[l] / __powidf2.
This supports __powidf2 by means of a double wrapper for already
existing f7_powi (renamed to __f7_powi by f7-renames.h).
It tweaks the implementation so that it does not perform trivial
multiplications with 1.0 any more, but instead uses a move.
It also fixes the last statement of f7_powi, which was wrong.
Notice that f7_powi was unused until now.
PR target/114981
libgcc/config/avr/libf7/
* libf7-common.mk (F7_ASM_PARTS): Add D_powi
* libf7-asm.sx (F7MOD_D_powi_, __powidf2): New module and function.
* libf7.c (f7_powi): Fix last (wrong) statement.
Tweak trivial multiplications with 1.0.
gcc/testsuite/
* gcc.target/avr/pr114981-powil.c: New test.
Diffstat (limited to 'libgcc/config/avr')
-rw-r--r-- | libgcc/config/avr/libf7/libf7-asm.sx | 12 | ||||
-rw-r--r-- | libgcc/config/avr/libf7/libf7-common.mk | 2 | ||||
-rw-r--r-- | libgcc/config/avr/libf7/libf7.c | 29 |
3 files changed, 35 insertions, 8 deletions
diff --git a/libgcc/config/avr/libf7/libf7-asm.sx b/libgcc/config/avr/libf7/libf7-asm.sx index 1ab9127..1f8f60a 100644 --- a/libgcc/config/avr/libf7/libf7-asm.sx +++ b/libgcc/config/avr/libf7/libf7-asm.sx @@ -1877,4 +1877,16 @@ ENDF call_ddd #include "f7-wraps.h" +;;; Some additional, singular wraps that don't match any pattern. + +;; double __powidf2 (double, int) ; __builtin_powi +#ifdef F7MOD_D_powi_ +_DEFUN __powidf2 + .global F7_NAME(powi) + ldi ZH, hi8(gs(F7_NAME(powi))) + ldi ZL, lo8(gs(F7_NAME(powi))) + F7jmp call_ddx +_ENDF __powidf2 +#endif /* F7MOD_D_powi_ */ + #endif /* !AVR_TINY */ diff --git a/libgcc/config/avr/libf7/libf7-common.mk b/libgcc/config/avr/libf7/libf7-common.mk index d541b48..5d41107 100644 --- a/libgcc/config/avr/libf7/libf7-common.mk +++ b/libgcc/config/avr/libf7/libf7-common.mk @@ -22,7 +22,7 @@ F7_ASM_PARTS += addsub_mant_scaled store load F7_ASM_PARTS += to_integer to_unsigned clz normalize_with_carry normalize F7_ASM_PARTS += store_expo sqrt16 sqrt_approx div -F7_ASM_PARTS += D_class D_fma +F7_ASM_PARTS += D_class D_fma D_powi F7_ASM_PARTS += D_isnan D_isinf D_isfinite D_signbit D_copysign D_neg D_fabs F7_ASM_PARTS += call_dd call_ddd diff --git a/libgcc/config/avr/libf7/libf7.c b/libgcc/config/avr/libf7/libf7.c index 369dbe2..375becb 100644 --- a/libgcc/config/avr/libf7/libf7.c +++ b/libgcc/config/avr/libf7/libf7.c @@ -1752,20 +1752,33 @@ void f7_powi (f7_t *cc, const f7_t *aa, int ii) { uint16_t u16 = ii; f7_t xx27, *xx2 = &xx27; + bool cc_is_one = true; + bool expo_is_neg = false; if (ii < 0) - u16 = -u16; + { + u16 = -u16; + expo_is_neg = true; + } f7_copy (xx2, aa); - f7_set_u16 (cc, 1); - while (1) { if (u16 & 1) - f7_Imul (cc, xx2); + { + if (cc_is_one) + { + // C *= X2 simplifies to C = X2. + f7_copy (cc, xx2); + cc_is_one = false; + } + else + f7_Imul (cc, xx2); + } - if (! f7_is_nonzero (cc)) + if (! cc_is_one + && ! f7_is_nonzero (cc)) break; u16 >>= 1; @@ -1774,8 +1787,10 @@ void f7_powi (f7_t *cc, const f7_t *aa, int ii) f7_Isquare (xx2); } - if (ii < 0) - f7_div1 (xx2, aa); + if (cc_is_one) + f7_set_u16 (cc, 1); + else if (expo_is_neg) + f7_div1 (cc, cc); } #endif // F7MOD_powi_ |