mulx.hpp 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Copyright 2022, 2023 Peter Dimov
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // https://www.boost.org/LICENSE_1_0.txt
  4. #ifndef BOOST_HASH_DETAIL_MULX_HPP
  5. #define BOOST_HASH_DETAIL_MULX_HPP
  6. #include <cstdint>
  7. #if defined(_MSC_VER)
  8. # include <intrin.h>
  9. #endif
  10. namespace boost
  11. {
  12. namespace hash_detail
  13. {
  14. #if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)
  15. __forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
  16. {
  17. std::uint64_t r2;
  18. std::uint64_t r = _umul128( x, y, &r2 );
  19. return r ^ r2;
  20. }
  21. #elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
  22. __forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
  23. {
  24. std::uint64_t r = x * y;
  25. std::uint64_t r2 = __umulh( x, y );
  26. return r ^ r2;
  27. }
  28. #elif defined(__SIZEOF_INT128__)
  29. inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
  30. {
  31. __uint128_t r = static_cast<__uint128_t>( x ) * y;
  32. return static_cast<std::uint64_t>( r ) ^ static_cast<std::uint64_t>( r >> 64 );
  33. }
  34. #else
  35. inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
  36. {
  37. std::uint64_t x1 = static_cast<std::uint32_t>( x );
  38. std::uint64_t x2 = x >> 32;
  39. std::uint64_t y1 = static_cast<std::uint32_t>( y );
  40. std::uint64_t y2 = y >> 32;
  41. std::uint64_t r3 = x2 * y2;
  42. std::uint64_t r2a = x1 * y2;
  43. r3 += r2a >> 32;
  44. std::uint64_t r2b = x2 * y1;
  45. r3 += r2b >> 32;
  46. std::uint64_t r1 = x1 * y1;
  47. std::uint64_t r2 = (r1 >> 32) + static_cast<std::uint32_t>( r2a ) + static_cast<std::uint32_t>( r2b );
  48. r1 = (r2 << 32) + static_cast<std::uint32_t>( r1 );
  49. r3 += r2 >> 32;
  50. return r1 ^ r3;
  51. }
  52. #endif
  53. } // namespace hash_detail
  54. } // namespace boost
  55. #endif // #ifndef BOOST_HASH_DETAIL_MULX_HPP