aboutsummaryrefslogtreecommitdiff
path: root/libgcc/config/avr
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2024-05-08 17:56:05 +0200
committerGeorg-Johann Lay <avr@gjlay.de>2024-05-08 19:04:06 +0200
commitde4eea7d7ea86e54843507c68d6672eca9d8c7bb (patch)
tree7d238cb292c1bad7eefff0135c4c523bcbda8bfb /libgcc/config/avr
parent2f00e6caca1a14dfe26e94f608e9d79a787ebe08 (diff)
downloadgcc-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.sx12
-rw-r--r--libgcc/config/avr/libf7/libf7-common.mk2
-rw-r--r--libgcc/config/avr/libf7/libf7.c29
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_