From a7c58453172679b7ca813565adedee821b8ae679 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Wed, 13 Feb 2019 11:49:31 +0700 Subject: osd: 64x64 multiply helpers (nw) Can we have these? I didn't attempt to add implementations for anything other than MSVC, but I believe gcc and clang for 64-bit targets have equivalents. --- src/osd/eivcx86.h | 20 +++++++++++++++++++ src/osd/eminline.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/osd/eivcx86.h b/src/osd/eivcx86.h index f913ac94624..3fd3e70948c 100644 --- a/src/osd/eivcx86.h +++ b/src/osd/eivcx86.h @@ -403,4 +403,24 @@ static inline float _recip_approx(float z) } #endif + +/*------------------------------------------------- + mul_64x64 - perform a signed 64 bit x 64 bit + multiply and return the full 128 bit result +-------------------------------------------------*/ + +#ifdef PTR64 +#define mul_64x64 _mul128 +#endif + + +/*------------------------------------------------- + mulu_64x64 - perform an unsigned 64 bit x 64 + bit multiply and return the full 128 bit result +-------------------------------------------------*/ + +#ifdef PTR64 +#define mulu_64x64 _umul128 +#endif + #endif // MAME_OSD_EIVCX86_H diff --git a/src/osd/eminline.h b/src/osd/eminline.h index bb0aec63468..1f543a21b36 100644 --- a/src/osd/eminline.h +++ b/src/osd/eminline.h @@ -260,6 +260,62 @@ inline float recip_approx(float value) #endif +/*------------------------------------------------- + mul_64x64 - perform a signed 64 bit x 64 bit + multiply and return the full 128 bit result +-------------------------------------------------*/ + +#ifndef mul_64x64 +inline int64_t mul_64x64(int64_t a, int64_t b, int64_t *hi) +{ + uint64_t const a_hi = uint32_t(a >> 32); + uint64_t const b_hi = uint32_t(b >> 32); + uint64_t const a_lo = uint32_t(a); + uint64_t const b_lo = uint32_t(b); + + uint64_t const ab_lo = a_lo * b_lo; + uint64_t const ab_m1 = a_hi * b_lo; + uint64_t const ab_m2 = a_lo * b_hi; + uint64_t const ab_hi = a_hi * b_hi; + uint64_t const carry = ((ab_lo >> 32) + uint32_t(ab_m1) + uint32_t(ab_m2)) >> 32; + + *hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry; + + // adjust for sign + if (a < 0) + *hi -= b; + if (b < 0) + *hi -= a; + + return ab_lo + (ab_m1 << 32) + (ab_m2 << 32); +} +#endif + + +/*------------------------------------------------- + mulu_64x64 - perform an unsigned 64 bit x 64 + bit multiply and return the full 128 bit result +-------------------------------------------------*/ + +#ifndef mulu_64x64 +inline uint64_t mulu_64x64(uint64_t a, uint64_t b, uint64_t *hi) +{ + uint64_t const a_hi = uint32_t(a >> 32); + uint64_t const b_hi = uint32_t(b >> 32); + uint64_t const a_lo = uint32_t(a); + uint64_t const b_lo = uint32_t(b); + + uint64_t const ab_lo = a_lo * b_lo; + uint64_t const ab_m1 = a_hi * b_lo; + uint64_t const ab_m2 = a_lo * b_hi; + uint64_t const ab_hi = a_hi * b_hi; + uint64_t const carry = ((ab_lo >> 32) + uint32_t(ab_m1) + uint32_t(ab_m2)) >> 32; + + *hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry; + + return ab_lo + (ab_m1 << 32) + (ab_m2 << 32); +} +#endif /*************************************************************************** INLINE BIT MANIPULATION FUNCTIONS -- cgit v1.2.3