mul128.hpp 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #ifndef BOOST_HASH2_DETAIL_MUL128_HPP_INCLUDED
  2. #define BOOST_HASH2_DETAIL_MUL128_HPP_INCLUDED
  3. // Copyright 2025 Christian Mazakas
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. #include <boost/hash2/detail/is_constant_evaluated.hpp>
  7. #include <boost/config.hpp>
  8. #include <cstdint>
  9. #if defined(_MSC_VER)
  10. #include <intrin.h>
  11. #endif
  12. namespace boost
  13. {
  14. namespace hash2
  15. {
  16. namespace detail
  17. {
  18. struct uint128
  19. {
  20. std::uint64_t low;
  21. std::uint64_t high;
  22. };
  23. BOOST_CXX14_CONSTEXPR inline uint128 mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
  24. {
  25. std::uint64_t lo_lo = ( x & 0xffffffff ) * ( y & 0xffffffff );
  26. std::uint64_t hi_lo = ( x >> 32 ) * ( y & 0xffffffff );
  27. std::uint64_t lo_hi = ( x & 0xffffffff ) * ( y >> 32 );
  28. std::uint64_t hi_hi = ( x >> 32 ) * ( y >> 32 );
  29. std::uint64_t cross = ( lo_lo >> 32 ) + ( hi_lo & 0xffffffff ) + lo_hi;
  30. std::uint64_t upper = ( hi_lo >> 32 ) + ( cross >> 32 ) + hi_hi;
  31. std::uint64_t lower = ( cross << 32 ) | ( lo_lo & 0xffffffff );
  32. uint128 r = { 0, 0 };
  33. r.low = lower;
  34. r.high = upper;
  35. return r;
  36. }
  37. BOOST_CXX14_CONSTEXPR inline uint128 mul128( std::uint64_t x, std::uint64_t y ) noexcept
  38. {
  39. #if defined(BOOST_HAS_INT128)
  40. __uint128_t product = __uint128_t( x ) * __uint128_t( y );
  41. uint128 r = { 0, 0 };
  42. r.low = static_cast<std::uint64_t>( product );
  43. r.high = static_cast<std::uint64_t>( product >> 64 );
  44. return r;
  45. #elif ( defined(_M_X64) || defined(_M_IA64) ) && !defined(_M_ARM64EC)
  46. if( !detail::is_constant_evaluated() )
  47. {
  48. uint128 r = { 0, 0 };
  49. std::uint64_t high_product = 0;
  50. r.low = _umul128( x, y, &high_product );
  51. r.high = high_product;
  52. return r;
  53. }
  54. else
  55. {
  56. return mul128_impl( x, y );
  57. }
  58. #elif defined(_M_ARM64) || defined(_M_ARM64EC)
  59. BOOST_CXX14_CONSTEXPR inline uint128 mul128_impl( std::uint64_t x, std::uint64_t y ) noexcept
  60. {
  61. if( !detail::is_constant_evaluated() )
  62. {
  63. uint128 r = { 0, 0 };
  64. r.low = x * y;
  65. r.high = __umulh( x, y );
  66. return r;
  67. }
  68. else
  69. {
  70. return mul128_impl( x, y );
  71. }
  72. #else
  73. return mul128_impl( x, y );
  74. #endif
  75. }
  76. } // namespace detail
  77. } // namespace hash2
  78. } // namespace boost
  79. #endif // #ifndef BOOST_HASH2_DETAIL_MUL128_HPP_INCLUDED