2
0
mirror of https://github.com/boostorg/hash2.git synced 2026-01-19 04:12:12 +00:00

Refactor detail/mul128.hpp

This commit is contained in:
Peter Dimov
2025-04-27 19:41:16 +03:00
parent 161b47e749
commit c445bcef57

View File

@@ -9,7 +9,7 @@
#include <boost/config.hpp>
#include <cstdint>
#if defined(BOOST_MSVC)
#if defined(_MSC_VER)
#include <intrin.h>
#endif
@@ -26,78 +26,6 @@ struct uint128_t
std::uint64_t high;
};
#if defined(BOOST_HAS_INT128)
BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
__uint128_t product = __uint128_t{ x } * __uint128_t{ y };
uint128_t r = { 0, 0 };
r.low = static_cast<std::uint64_t>( product );
r.high = static_cast<std::uint64_t>( product >> 64 );
return r;
}
#elif ( defined(_M_X64) || defined(_M_IA64) ) && !defined(_M_ARM64EC)
BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
if( !detail::is_constant_evaluated() )
{
uint128_t r = { 0, 0 };
std::uint64_t high_product = 0;
r.low = _umul128( x, y, &high_product );
r.high = high_product;
return r;
}
else
{
std::uint64_t lo_lo = ( x & 0xffffffff ) * ( y & 0xffffffff );
std::uint64_t hi_lo = ( x >> 32 ) * ( y & 0xffffffff );
std::uint64_t lo_hi = ( x & 0xffffffff ) * ( y >> 32 );
std::uint64_t hi_hi = ( x >> 32 ) * ( y >> 32 );
std::uint64_t cross = ( lo_lo >> 32 ) + ( hi_lo & 0xffffffff ) + lo_hi;
std::uint64_t upper = ( hi_lo >> 32 ) + ( cross >> 32 ) + hi_hi;
std::uint64_t lower = ( cross << 32 ) | ( lo_lo & 0xffffffff );
uint128_t r = { 0, 0 };
r.low = lower;
r.high = upper;
return r;
}
}
#elif defined(_M_ARM64) || defined(_M_ARM64EC)
BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
if( !detail::is_constant_evaluated() )
{
uint128_t r = { 0, 0 };
r.low = x * y;
r.high = __umulh( x, y );
return r;
}
else
{
std::uint64_t lo_lo = ( x & 0xffffffff ) * ( y & 0xffffffff );
std::uint64_t hi_lo = ( x >> 32 ) * ( y & 0xffffffff );
std::uint64_t lo_hi = ( x & 0xffffffff ) * ( y >> 32 );
std::uint64_t hi_hi = ( x >> 32 ) * ( y >> 32 );
std::uint64_t cross = ( lo_lo >> 32 ) + ( hi_lo & 0xffffffff ) + lo_hi;
std::uint64_t upper = ( hi_lo >> 32 ) + ( cross >> 32 ) + hi_hi;
std::uint64_t lower = ( cross << 32 ) | ( lo_lo & 0xffffffff );
uint128_t r = { 0, 0 };
r.low = lower;
r.high = upper;
return r;
}
}
#else
BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
std::uint64_t lo_lo = ( x & 0xffffffff ) * ( y & 0xffffffff );
@@ -115,11 +43,53 @@ BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64
return r;
}
#endif
BOOST_CXX14_CONSTEXPR inline uint128_t mul128( std::uint64_t x, std::uint64_t y ) noexcept
{
#if defined(BOOST_HAS_INT128)
__uint128_t product = __uint128_t( x ) * __uint128_t( y );
uint128_t r = { 0, 0 };
r.low = static_cast<std::uint64_t>( product );
r.high = static_cast<std::uint64_t>( product >> 64 );
return r;
#elif ( defined(_M_X64) || defined(_M_IA64) ) && !defined(_M_ARM64EC)
if( !detail::is_constant_evaluated() )
{
uint128_t r = { 0, 0 };
std::uint64_t high_product = 0;
r.low = _umul128( x, y, &high_product );
r.high = high_product;
return r;
}
else
{
return mul128_impl( x, y );
}
#elif defined(_M_ARM64) || defined(_M_ARM64EC)
BOOST_CXX14_CONSTEXPR inline uint128_t mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
{
if( !detail::is_constant_evaluated() )
{
uint128_t r = { 0, 0 };
r.low = x * y;
r.high = __umulh( x, y );
return r;
}
else
{
return mul128_impl( x, y );
}
#else
return mul128_impl( x, y );
#endif
}
} // namespace detail