[glibc/azanella/clang] Add umul_ppmm to gmp-arch.hdoc

Adhemerval Zanella azanella@sourceware.org
Tue Oct 28 17:08:16 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=7bb95ba3a291b213bc3240f966ba2efff31c18ed

commit 7bb95ba3a291b213bc3240f966ba2efff31c18ed
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Fri Oct 24 14:17:05 2025 -0300

    Add umul_ppmm to gmp-arch.hdoc
    
    To enable “longlong.h” removal, the umul_ppmm is moved to a gmp-arch.h.
    The generic implementation now uses a static inline, which provides
    better type checking than the GNU extension to cast the asm constraint
    (and it works better with clang).
    
    Most of the architecture uses the generic implementation, which is
    expanded from a macro, except for alpha, arm, hppa, x86, m68k, mips,
    powerpc, and sparc.  I kept only x86 optimization, where there is no
    easy way to emit mul{q}. For the rest, the compiler generates good
    enough code.

Diff:
---
 sysdeps/generic/gmp-arch.h | 40 ++++++++++++++++++++++++++++++++++++++++
 sysdeps/x86/gmp-arch.h     | 21 +++++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/sysdeps/generic/gmp-arch.h b/sysdeps/generic/gmp-arch.h
index 3ec144562a..f5d6495f2b 100644
--- a/sysdeps/generic/gmp-arch.h
+++ b/sysdeps/generic/gmp-arch.h
@@ -35,6 +35,46 @@ ll_highpart (mp_limb_t t)
   return t >> (BITS_PER_MP_LIMB / 2);
 }
 
+/* umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two
+   UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype
+   word product in HIGH_PROD and LOW_PROD.  */
+static __always_inline void
+umul_ppmm_generic (mp_limb_t *w1, mp_limb_t *w0, mp_limb_t u, mp_limb_t v)
+{
+#if __WORDSIZE == 32
+  uint64_t t0 = (uint64_t)u * v;
+  *w1 = t0 >> 32;
+  *w0 = t0;
+#else
+  mp_limb_t ul = ll_lowpart (u);
+  mp_limb_t uh = ll_highpart (u);
+  mp_limb_t vl = ll_lowpart (v);
+  mp_limb_t vh = ll_highpart (v);
+
+  mp_limb_t x0 = ul * vl;
+  mp_limb_t x1 = ul * vh;
+  mp_limb_t x2 = uh * vl;
+  mp_limb_t x3 = uh * vh;
+
+  x1 += ll_highpart (x0);
+  x1 += x2;
+  if (x1 < x2)
+    x3 += LL_B;
+
+  *w1 = x3 + ll_highpart (x1);
+  *w0 = ll_lowpart (x1) * LL_B + ll_lowpart (x0);
+#endif
+}
+#undef umul_ppmm
+#define umul_ppmm(__w1, __w0, __u, __v)			\
+  ({							\
+    __typeof (__w0) __w0t;				\
+    __typeof (__w1) __w1t;				\
+    umul_ppmm_generic (&__w1t, &__w0t, __u, __v);	\
+    __w1 = __w1t;					\
+    __w0 = __w0t;					\
+  })
+
 /* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
    denominator) divides a UDWtype, composed by the UWtype integers
    HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
diff --git a/sysdeps/x86/gmp-arch.h b/sysdeps/x86/gmp-arch.h
index 45f047e1b6..c3aa0f2e3b 100644
--- a/sysdeps/x86/gmp-arch.h
+++ b/sysdeps/x86/gmp-arch.h
@@ -21,6 +21,27 @@
 
 #include <gmp.h>
 
+static __always_inline void
+umul_ppmm_generic (mp_limb_t *w1, mp_limb_t *w0, mp_limb_t u, mp_limb_t v)
+{
+#ifdef __x86_64__
+  asm ("mul{q} %3"
+       : "=a" (*w0),
+         "=d" (*w1)
+       : "%0" (u),
+         "rm" (v));
+#else
+  asm ("mul{l} %3"
+       : "=a" (*w0),
+         "=d" (*w1)
+       : "%0" (u),
+         "rm" (v));
+#endif
+}
+#undef umul_ppmm
+#define umul_ppmm(__w1, __w0, __u, __v) \
+  umul_ppmm_generic (&__w1, &__w0, __u, __v)
+
 static __always_inline void
 udiv_qrnnd_x86 (mp_limb_t *q, mp_limb_t *r, mp_limb_t n1, mp_limb_t n0,
 		mp_limb_t d)


More information about the Glibc-cvs mailing list