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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user