https://gcc.gnu.org/g:adba85bb63a45d7d668501c11bdf9772cc00b7b8

commit r13-8736-gadba85bb63a45d7d668501c11bdf9772cc00b7b8
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Wed May 8 17:56:05 2024 +0200

    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.
    
    (cherry picked from commit de4eea7d7ea86e54843507c68d6672eca9d8c7bb)

Diff:
---
 gcc/testsuite/gcc.target/avr/pr114981-powil.c | 33 +++++++++++++++++++++++++++
 libgcc/config/avr/libf7/libf7-asm.sx          | 12 ++++++++++
 libgcc/config/avr/libf7/libf7-common.mk       |  2 +-
 libgcc/config/avr/libf7/libf7.c               | 29 +++++++++++++++++------
 4 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/gcc/testsuite/gcc.target/avr/pr114981-powil.c 
b/gcc/testsuite/gcc.target/avr/pr114981-powil.c
new file mode 100644
index 000000000000..70f8e796c654
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr114981-powil.c
@@ -0,0 +1,33 @@
+/* { dg-do run { target { ! avr_tiny } } } */
+/* { dg-additional-options "-Os" } */
+
+const long double vals[] =
+  {
+    0.0625L, -0.125L, 0.25L, -0.5L,
+    1.0L,
+    -2.0L, 4.0L, -8.0L, 16.0L
+  };
+
+#define ARRAY_SIZE(X) ((int) (sizeof(X) / sizeof(*X)))
+
+__attribute__((noinline,noclone))
+void test1 (long double x)
+{
+  int i;
+
+  for (i = 0; i < ARRAY_SIZE (vals); ++i)
+    {
+      long double val0 = vals[i];
+      long double val1 = __builtin_powil (x, i - 4);
+      __asm ("" : "+r" (val0));
+
+      if (val0 != val1)
+       __builtin_exit (__LINE__);
+    }
+}
+
+int main (void)
+{
+  test1 (-2.0L);
+  return 0;
+}
diff --git a/libgcc/config/avr/libf7/libf7-asm.sx 
b/libgcc/config/avr/libf7/libf7-asm.sx
index b00f75994964..df315d35c73e 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 d541b48ff3ca..5d411071c8e4 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 fd7059d6c65a..a769f311d958 100644
--- a/libgcc/config/avr/libf7/libf7.c
+++ b/libgcc/config/avr/libf7/libf7.c
@@ -1749,20 +1749,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;
@@ -1771,8 +1784,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_

Reply via email to