]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
AVR: Tweak lib1funcs-fixed.S::__mulQ64_work.
authorGeorg-Johann Lay <avr@gjlay.de>
Wed, 22 Jul 2026 10:25:30 +0000 (12:25 +0200)
committerGeorg-Johann Lay <avr@gjlay.de>
Wed, 22 Jul 2026 10:28:10 +0000 (12:28 +0200)
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.

gcc/testsuite/gcc.target/avr/fx64-mul-1.c [moved from gcc/testsuite/gcc.target/avr/fx24-mul.c with 59% similarity]
gcc/testsuite/gcc.target/avr/fx64-mul-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/avr/fx64-mul.h [new file with mode: 0644]
libgcc/config/avr/lib1funcs-fixed.S

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 6cc0d75b8cb04f29227f4a365b7f6fafd5ffe103..fb342b3cce78daacd0e36f860a8d28643a7f66ec 100644 (file)
@@ -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 (file)
index 0000000..a679c01
--- /dev/null
@@ -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 (file)
index 0000000..5c935d5
--- /dev/null
@@ -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
index 52e32a059efdac6b6b7d39c46d06f78ad51ee846..e7f21ceca17ec9f66af2831bac5b7857762c58bf 100644 (file)
@@ -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 */