From 7040c57750e97fd1b09ac39ca6222ad915ec8de8 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 8 Dec 2022 21:40:13 +0200 Subject: [PATCH] Add mulx_mix --- include/boost/unordered/detail/foa.hpp | 10 ++ include/boost/unordered/detail/mulx.hpp | 118 ++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 include/boost/unordered/detail/mulx.hpp diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 89d79dae..289ea457 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -760,6 +761,15 @@ struct xmx_mix } }; +struct mulx_mix +{ + template + static inline std::size_t mix(const Hash& h,const T& x) + { + return mulx(h(x)); + } +}; + /* boost::core::countr_zero has a potentially costly check for * the case x==0. */ diff --git a/include/boost/unordered/detail/mulx.hpp b/include/boost/unordered/detail/mulx.hpp new file mode 100644 index 00000000..93baea9f --- /dev/null +++ b/include/boost/unordered/detail/mulx.hpp @@ -0,0 +1,118 @@ +#ifndef BOOST_UNORDERED_DETAIL_MULX_HPP +#define BOOST_UNORDERED_DETAIL_MULX_HPP + +// Copyright 2022 Peter Dimov. +// Copyright 2022 Joaquin M Lopez Munoz. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#if defined(_MSC_VER) && !defined(__clang__) +# include +#endif + +namespace boost { +namespace unordered { +namespace detail { + +// Bit mixer based on the mulx primitive + +#if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__) + +__forceinline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y ) +{ + boost::uint64_t r2; + boost::uint64_t r = _umul128( x, y, &r2 ); + return r ^ r2; +} + +#elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__) + +__forceinline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y ) +{ + boost::uint64_t r = x * y; + boost::uint64_t r2 = __umulh( x, y ); + return r ^ r2; +} + +#elif defined(__SIZEOF_INT128__) + +inline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y ) +{ + __uint128_t r = (__uint128_t)x * y; + return (boost::uint64_t)r ^ (boost::uint64_t)( r >> 64 ); +} + +#else + +inline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y ) +{ + boost::uint64_t x1 = (boost::uint32_t)x; + boost::uint64_t x2 = x >> 32; + + boost::uint64_t y1 = (boost::uint32_t)y; + boost::uint64_t y2 = y >> 32; + + boost::uint64_t r3 = x2 * y2; + + boost::uint64_t r2a = x1 * y2; + + r3 += r2a >> 32; + + boost::uint64_t r2b = x2 * y1; + + r3 += r2b >> 32; + + boost::uint64_t r1 = x1 * y1; + + boost::uint64_t r2 = (r1 >> 32) + (boost::uint32_t)r2a + (boost::uint32_t)r2b; + + r1 = (r2 << 32) + (boost::uint32_t)r1; + r3 += r2 >> 32; + + return r1 ^ r3; +} + +#endif + +inline boost::uint32_t mulx32( boost::uint32_t x, boost::uint32_t y ) +{ + boost::uint64_t r = (boost::uint64_t)x * y; + return (boost::uint32_t)r ^ (boost::uint32_t)(r >> 32); +} + +#if defined(SIZE_MAX) +#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0 +#define BOOST_UNORDERED_64B_ARCHITECTURE /* >64 bits assumed as 64 bits */ +#endif +#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */ +#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0 +#define BOOST_UNORDERED_64B_ARCHITECTURE +#endif +#endif + +inline std::size_t mulx( std::size_t x ) noexcept +{ +#if defined(BOOST_UNORDERED_64B_ARCHITECTURE) + + return (std::size_t)mulx64( (boost::uint64_t)x, 0x9E3779B97F4A7C15ull ); + +#else /* 32 bits assumed */ + + return mulx32( x, 0x9E3779B9u ); + +#endif +} + +#ifdef BOOST_UNORDERED_64B_ARCHITECTURE +#undef BOOST_UNORDERED_64B_ARCHITECTURE +#endif + +} // namespace detail +} // namespace unordered +} // namespace boost + +#endif // #ifndef BOOST_UNORDERED_DETAIL_MULX_HPP