[gcc r17-2615] AVR: Tweak lib1funcs-fixed.S::__mulQ64_work.

Georg-Johann Lay via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:65b50ebf4bbdf39388cd83030d9441111663604b

commit r17-2615-g65b50ebf4bbdf39388cd83030d9441111663604b
Author: Georg-Johann Lay <[email protected]>
Date:   Wed Jul 22 12:25:30 2026 +0200

    AVR: Tweak lib1funcs-fixed.S::__mulQ64_work.
    
    This patch
    - Tweaks the signed overflow handling in __mulQ64_work.
    - Rename misnomed fx24-mul.c to fx64-mul-1.c.
    - Adds more test cases in fx64-mul-2.c.
    
    libgcc/
            * config/avr/lib1funcs-fixed.S (__mulQ64_work): Tweak
            overflow handling.  Use __negsi2 (non-saturating negation)
            to negate.
    gcc/testsuite/
            * gcc.target/avr/fx24-mul.c: Renamed to...
            * gcc.target/avr/fx64-mul-1.c: ...this.
            * gcc.target/avr/fx64-mul-2.c: New test.
            * gcc.target/avr/fx64-mul.h: New file.

Diff:
---
 .../gcc.target/avr/{fx24-mul.c => fx64-mul-1.c}    | 60 +-------------------
 gcc/testsuite/gcc.target/avr/fx64-mul-2.c          | 65 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/avr/fx64-mul.h            | 60 ++++++++++++++++++++
 libgcc/config/avr/lib1funcs-fixed.S                | 44 +++++----------
 4 files changed, 141 insertions(+), 88 deletions(-)

diff --git a/gcc/testsuite/gcc.target/avr/fx24-mul.c b/gcc/testsuite/gcc.target/avr/fx64-mul-1.c
similarity index 59%
rename from gcc/testsuite/gcc.target/avr/fx24-mul.c
rename to gcc/testsuite/gcc.target/avr/fx64-mul-1.c
index 6cc0d75b8cb0..fb342b3cce78 100644
--- a/gcc/testsuite/gcc.target/avr/fx24-mul.c
+++ b/gcc/testsuite/gcc.target/avr/fx64-mul-1.c
@@ -3,63 +3,7 @@
 
 // !!! Requires the fx64 <-> float conversions from AVR-LibC.
 
-#include <stdfix.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <avr/pgmspace.h>
-
-#define NI __attribute((noipa))
-
-typedef long accum lk_t;
-typedef long long accum llk_t;
-typedef long long fract llr_t;
-
-typedef unsigned long accum ulk_t;
-typedef unsigned long long accum ullk_t;
-typedef unsigned long long fract ullr_t;
-
-// Values are in fmin <= x < fmax.
-#define fmax_llr 1.0f
-#define fmin_llr (-fmax_llr)
-#define fmax_ullr fmax_llr
-#define fmin_ullr 0.0f
-
-#define fmax_lk 0x1.0p32f
-#define fmin_lk (-fmax_lk)
-#define fmax_ulk fmax_lk
-#define fmin_ulk 0.0f
-
-#define fmax_llk 0x1.0p16f
-#define fmin_llk (-fmax_llk)
-#define fmax_ullk fmax_llk
-#define fmin_ullk 0.0f
-
-#define UMAX 0xffffffffffffffff
-#define SMAX 0x7fffffffffffffff
-#define SMIN 0x8000000000000000
-
-// Values are in min <= x <= max.
-#define max_lk lkbits (SMAX)
-#define min_lk lkbits (SMIN)
-#define max_ulk ulkbits (UMAX)
-#define min_ulk ulkbits (0)
-
-#define max_llk llkbits (SMAX)
-#define min_llk llkbits (SMIN)
-#define max_ullk ullkbits (UMAX)
-#define min_ullk ullkbits (0)
-
-#define max_llr llrbits (SMAX)
-#define min_llr llrbits (SMIN)
-#define max_ullr ullrbits (UMAX)
-#define min_ullr ullrbits (0)
-
-#define id_lk   10
-#define id_ulk  20
-#define id_llk  30
-#define id_ullk 40
-#define id_llr  50
-#define id_ullr 60
+#include "fx64-mul.h"
 
 #define MK_TEST(fx)				    \
   NI bool in_range_##fx (float x)		    \
@@ -111,8 +55,6 @@ NI void test_mul (float a, float b)
   test_mul_ullr (a, b);
 }
 
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
-
 // Results / arguments must be representable as float, so no rounding occurs.
 // No-overflow results must be representable as fixed, so no rounding occurs.
 const PROGMEM float fvals[] =
diff --git a/gcc/testsuite/gcc.target/avr/fx64-mul-2.c b/gcc/testsuite/gcc.target/avr/fx64-mul-2.c
new file mode 100644
index 000000000000..a679c010928f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/fx64-mul-2.c
@@ -0,0 +1,65 @@
+/* { dg-do run { target { ! avr_tiny } } } */
+/* { dg-additional-options { -std=gnu99 -Os -mcall-prologues } } */
+
+// !!! Requires the fx64 <-> float conversions from AVR-LibC.
+
+#include "fx64-mul.h"
+
+NI void test_mul (float fa, float fb, uint64_t res)
+{
+  lk_t a = (lk_t) fa;
+  lk_t b = (lk_t) fb;
+  if (a * b != lkbits (res))
+    exit (id_lk + 4);
+}
+
+void test (void)
+{
+  const float e16 = 0x1p-16f;
+  const float e15 = 0x1p-15f;
+
+  const float p0 = 0x1.0p+0f;
+  const float p1 = 0x1.0p+1f;
+  const float p16 = 0x1.0p+16f;
+  const float p17 = 0x1.0p+17f;
+  const float p31 = 0x1.0p+31f;
+  const float p32 = 0x1.0p+32f;
+
+  test_mul (-p16, -p16, SMAX);
+  test_mul (+p16, +p16, SMAX);
+  test_mul (+p16, -p16, SMIN);
+  test_mul (-p16, +p16, SMIN);
+
+  test_mul (-p16, -p17, SMAX);
+  test_mul (+p16, +p17, SMAX);
+  test_mul (+p16, -p17, SMIN);
+  test_mul (-p16, +p17, SMIN);
+
+  test_mul (-p17, -p16, SMAX);
+  test_mul (+p17, +p16, SMAX);
+  test_mul (+p17, -p16, SMIN);
+  test_mul (-p17, +p16, SMIN);
+
+  test_mul (+e16, +e15, 1);
+  test_mul (-e16, -e15, 1);
+  test_mul (-e16, +e15, -1ull);
+  test_mul (+e16, -e15, -1ull);
+
+  test_mul (+e16, +e16, 0);
+  test_mul (-e16, +e16, 0);
+  test_mul (-e16, -e16, 0);
+
+  test_mul (-p32, -p0, SMAX);
+  test_mul (-p32, +p0, SMIN);
+
+  test_mul (-p31, -p1, SMAX);
+  test_mul (-p31, +p1, SMIN);
+  test_mul (+p31, +p1, SMAX);
+  test_mul (+p31, -p1, SMIN);
+}
+
+int main (void)
+{
+  test ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/fx64-mul.h b/gcc/testsuite/gcc.target/avr/fx64-mul.h
new file mode 100644
index 000000000000..5c935d58c1a7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/fx64-mul.h
@@ -0,0 +1,60 @@
+// !!! Requires the fx64 <-> float conversions from AVR-LibC.
+
+#include <stdfix.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <avr/pgmspace.h>
+
+#define NI __attribute((noipa))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
+
+typedef long accum lk_t;
+typedef long long accum llk_t;
+typedef long long fract llr_t;
+
+typedef unsigned long accum ulk_t;
+typedef unsigned long long accum ullk_t;
+typedef unsigned long long fract ullr_t;
+
+// Values are in fmin <= x < fmax.
+#define fmax_llr 1.0f
+#define fmin_llr (-fmax_llr)
+#define fmax_ullr fmax_llr
+#define fmin_ullr 0.0f
+
+#define fmax_lk 0x1.0p32f
+#define fmin_lk (-fmax_lk)
+#define fmax_ulk fmax_lk
+#define fmin_ulk 0.0f
+
+#define fmax_llk 0x1.0p16f
+#define fmin_llk (-fmax_llk)
+#define fmax_ullk fmax_llk
+#define fmin_ullk 0.0f
+
+#define UMAX 0xffffffffffffffff
+#define SMAX 0x7fffffffffffffff
+#define SMIN 0x8000000000000000
+
+// Values are in min <= x <= max.
+#define max_lk lkbits (SMAX)
+#define min_lk lkbits (SMIN)
+#define max_ulk ulkbits (UMAX)
+#define min_ulk ulkbits (0)
+
+#define max_llk llkbits (SMAX)
+#define min_llk llkbits (SMIN)
+#define max_ullk ullkbits (UMAX)
+#define min_ullk ullkbits (0)
+
+#define max_llr llrbits (SMAX)
+#define min_llr llrbits (SMIN)
+#define max_ullr ullrbits (UMAX)
+#define min_ullr ullrbits (0)
+
+#define id_lk   10
+#define id_ulk  20
+#define id_llk  30
+#define id_ullk 40
+#define id_llr  50
+#define id_ullr 60
diff --git a/libgcc/config/avr/lib1funcs-fixed.S b/libgcc/config/avr/lib1funcs-fixed.S
index 52e32a059efd..e7f21ceca17e 100644
--- a/libgcc/config/avr/lib1funcs-fixed.S
+++ b/libgcc/config/avr/lib1funcs-fixed.S
@@ -1155,7 +1155,7 @@ DEFUN __mulQ64_work
     push    __tmp_reg__
 
     ;; A = |A|
-    .call_if_neg  A7, __ssneg_8
+    .call_if_neg  A7, __negdi2
 
     ;; Stash away |A|
     wmov    r26, A6
@@ -1172,7 +1172,7 @@ DEFUN __mulQ64_work
 
     ;; A = |B|
     mov8    A0, B0
-    .call_if_neg  A7, __ssneg_8
+    .call_if_neg  A7, __negdi2
 
     ;; Restore B = |A|
     wmov    B6, r26
@@ -1195,9 +1195,6 @@ DEFUN __mulQ64_work
     ;; C = T = LSB (bit -1) from the unsigned mult.
     bld     __tmp_reg__, 7
     rol     __tmp_reg__
-    ;; T = result sign
-    pop     __tmp_reg__
-    bst     __tmp_reg__, 7
     ;; Adjust for signed Q formats that have one FBIT less.
     rol     A0
     rol     A1
@@ -1207,41 +1204,30 @@ DEFUN __mulQ64_work
     rol     A5
     rol     A6
     rol     A7
-    brts .Lneg
 
-    ;; Result must be is >= 0
-    ;; C = 1: Positive overflow
+    ;; r30.7 = result sign
+    pop     r30
+
+    ;; Handle overflow.
     brcs .Lsaturate
-    ;; A < 0: Positive overflow
-    sec
+    ;; In the negative result case, A = 0x80.. is no overflow,
+    ;; but treating it as such keeps the value unchanged.
     brmi .Lsaturate
+
+    ;; Handle negation.
+    sbrs    r30, 7
     ret
+    XJMP    __negdi2
 
-.L0x80:
-    ;; Return 0x80..
-    clc
 .Lsaturate:
+    ;; r30.7 = 0 -> 0x7f...
+    ;; r30.7 = 1 -> 0x80...
+    cpi     r30, 0x80
     ;; C = 1 -> 0x7f...
     ;; C = 0 -> 0x80...
     XCALL   __sbc_8
     subi    A7, 0x80
     ret
-
-.Lneg:
-    ;; Result must be <= 0
-    brcs .L0x80
-    XCALL   __negdi2
-    brmi 9f
-    ;; Values that are > 0 after the negation are overflow.
-    sbiw    A6, 0
-    sbci    A5, 0
-    sbci    A4, 0
-    sbci    A3, 0
-    sbci    A2, 0
-    sbci    A1, 0
-    sbci    A0, 0
-    brne .L0x80
-9:  ret
 ENDF __mulQ64_work
 #endif /* L_mulQ64_work */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.