[PATCH 1/3] mpi/longlong: provide generic implementation using double word type

Jussi Kivilinna jussi.kivilinna at iki.fi
Tue Oct 4 20:48:15 CEST 2022


* configure.ac: Add check for 'unsigned __int128'.
* mpi/longlong.h (UDWtype): Define for 32-bit or 64-bit when
'unsigned long long' or 'unsigned __int128' is available.
(add_ssaaaa, sub_ddmmss, umul_ppmm, udiv_qrnnd) [UDWtype]: New.
--

New generic longlong.h implementation by using 'unsigned long long'
on 32-bit and 'unsigned __int128' on 64-bit (for new architectures like
RISC-V).

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 configure.ac   |  1 +
 mpi/longlong.h | 75 ++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index c39257b5..6f68a945 100644
--- a/configure.ac
+++ b/configure.ac
@@ -360,6 +360,7 @@ AC_CHECK_SIZEOF(unsigned short, 2)
 AC_CHECK_SIZEOF(unsigned int, 4)
 AC_CHECK_SIZEOF(unsigned long, 4)
 AC_CHECK_SIZEOF(unsigned long long, 0)
+AC_CHECK_SIZEOF(unsigned __int128, 0)
 AC_CHECK_SIZEOF(void *, 0)
 
 AC_TYPE_UINTPTR_T
diff --git a/mpi/longlong.h b/mpi/longlong.h
index c299534c..6a829f49 100644
--- a/mpi/longlong.h
+++ b/mpi/longlong.h
@@ -20,18 +20,28 @@ along with this file; see the file COPYING.LIB.  If not, write to
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 MA 02111-1307, USA. */
 
+/* On 32-bit, use 64-bit 'unsigned long long' for UDWtype, if available. */
+#if !defined (UDWtype) && SIZEOF_UNSIGNED_LONG_LONG * 8 == W_TYPE_SIZE * 2
+#  define UDWtype unsigned long long
+#endif
+
+/* On 64-bit, use 128-bit 'unsigned __int128' for UDWtype, if available. */
+#if !defined (UDWtype) && SIZEOF_UNSIGNED___INT128 * 8 == W_TYPE_SIZE * 2
+#  define UDWtype unsigned __int128
+#endif
+
 /* You have to define the following before including this file:
 
-   UWtype -- An unsigned type, default type for operations (typically a "word")
+   UWtype -- An unsigned type, default type for operations (typically a "word").
    UHWtype -- An unsigned type, at least half the size of UWtype.
-   UDWtype -- An unsigned type, at least twice as large a UWtype
-   W_TYPE_SIZE -- size in bits of UWtype
+   UDWtype -- An unsigned type, at least twice as large a UWtype.
+   W_TYPE_SIZE -- size in bits of UWtype.
 
    SItype, USItype -- Signed and unsigned 32 bit types.
    DItype, UDItype -- Signed and unsigned 64 bit types.
 
-   On a 32 bit machine UWtype should typically be USItype;
-   on a 64 bit machine, UWtype should typically be UDItype.
+   On a 32 bit machine UWtype should typically be USItype.
+   On a 64 bit machine, UWtype should typically be UDItype.
 */
 
 #define __BITS4 (W_TYPE_SIZE / 4)
@@ -1617,7 +1627,21 @@ typedef unsigned int UTItype __attribute__ ((mode (TI)));
 
 /* If this machine has no inline assembler, use C macros.  */
 
-#if !defined (add_ssaaaa)
+#if !defined (add_ssaaaa) && defined (UDWtype)
+/* Use double word type when available. */
+#  define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    UDWtype __audw = (ah);						\
+    UDWtype __budw = (bh);						\
+    __audw <<= W_TYPE_SIZE;						\
+    __audw |= (al);							\
+    __budw <<= W_TYPE_SIZE;						\
+    __budw |= (bl);							\
+    __audw += __budw;							\
+    (sh) = (UWtype)(__audw >> W_TYPE_SIZE);				\
+    (sl) = (UWtype)(__audw); 						\
+  } while (0)
+#elif !defined (add_ssaaaa)
 #  define add_ssaaaa(sh, sl, ah, al, bh, bl) \
   do {									\
     UWtype __x; 							\
@@ -1627,7 +1651,21 @@ typedef unsigned int UTItype __attribute__ ((mode (TI)));
   } while (0)
 #endif
 
-#if !defined (sub_ddmmss)
+#if !defined (sub_ddmmss) && defined (UDWtype)
+/* Use double word type when available. */
+#  define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    UDWtype __audw = (ah);						\
+    UDWtype __budw = (bh);						\
+    __audw <<= W_TYPE_SIZE;						\
+    __audw |= (al);							\
+    __budw <<= W_TYPE_SIZE;						\
+    __budw |= (bl);							\
+    __audw -= __budw;							\
+    (sh) = (UWtype)(__audw >> W_TYPE_SIZE);				\
+    (sl) = (UWtype)(__audw); 						\
+  } while (0)
+#elif !defined (sub_ddmmss)
 #  define sub_ddmmss(sh, sl, ah, al, bh, bl) \
   do {									\
     UWtype __x; 							\
@@ -1637,7 +1675,15 @@ typedef unsigned int UTItype __attribute__ ((mode (TI)));
   } while (0)
 #endif
 
-#if !defined (umul_ppmm)
+#if !defined (umul_ppmm) && defined (UDWtype)
+#  define umul_ppmm(w1, w0, u, v) 					\
+  do {									\
+    UDWtype __x = (u);							\
+    __x *= (v);								\
+    (w1) = (UWtype)(__x >> W_TYPE_SIZE);				\
+    (w0) = (UWtype)(__x);						\
+  } while (0)
+#elif !defined (umul_ppmm)
 #  define umul_ppmm(w1, w0, u, v) 					\
   do {									\
     UWtype __x0, __x1, __x2, __x3;					\
@@ -1712,6 +1758,19 @@ typedef unsigned int UTItype __attribute__ ((mode (TI)));
     (r) = __r0; 							\
   } while (0)
 
+/* Use double word type if available. */
+#if !defined (udiv_qrnnd) && defined (UDWtype)
+#  define udiv_qrnnd(q, r, nh, nl, d) \
+  do {									\
+    UWtype __d = (d);							\
+    UDWtype __nudw = (nh);						\
+    __nudw <<= W_TYPE_SIZE;						\
+    __nudw |= (nl);							\
+    (q) = (UWtype)(__nudw / __d);					\
+    (r) = (UWtype)(__nudw % __d);					\
+  } while (0)
+#endif
+
 /* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
    __udiv_w_sdiv (defined in libgcc or elsewhere).  */
 #if !defined (udiv_qrnnd) && defined (sdiv_qrnnd)
-- 
2.34.1




More information about the Gcrypt-devel mailing list