mulx64.hpp 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /* Copyright 2022 Peter Dimov.
  2. * Copyright 2025 Joaquin M Lopez Munoz.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. *
  7. * See https://www.boost.org/libs/bloom for library home page.
  8. */
  9. #ifndef BOOST_BLOOM_DETAIL_MULX64_HPP
  10. #define BOOST_BLOOM_DETAIL_MULX64_HPP
  11. #include <climits>
  12. #include <cstddef>
  13. #include <cstdint>
  14. #if defined(_MSC_VER)&&!defined(__clang__)
  15. #include <intrin.h>
  16. #endif
  17. namespace boost{
  18. namespace bloom{
  19. namespace detail{
  20. #if defined(_MSC_VER)&&defined(_M_X64)&&!defined(__clang__)
  21. __forceinline std::uint64_t umul128(
  22. std::uint64_t x,std::uint64_t y,std::uint64_t& hi)
  23. {
  24. return _umul128(x,y,&hi);
  25. }
  26. #elif defined(_MSC_VER)&&defined(_M_ARM64)&&!defined(__clang__)
  27. __forceinline std::uint64_t umul128(
  28. std::uint64_t x,std::uint64_t y,std::uint64_t& hi)
  29. {
  30. hi=__umulh(x,y);
  31. return x*y;
  32. }
  33. #elif defined(__SIZEOF_INT128__)
  34. /* NOLINTNEXTLINE(readability-redundant-inline-specifier) */
  35. inline std::uint64_t umul128(
  36. std::uint64_t x,std::uint64_t y,std::uint64_t& hi)
  37. {
  38. __uint128_t r=(__uint128_t)x*y;
  39. hi=(std::uint64_t)(r>>64);
  40. return (std::uint64_t)r;
  41. }
  42. #else
  43. /* NOLINTNEXTLINE(readability-redundant-inline-specifier) */
  44. inline std::uint64_t umul128(
  45. std::uint64_t x,std::uint64_t y,std::uint64_t& hi)
  46. {
  47. std::uint64_t x1=(std::uint32_t)x;
  48. std::uint64_t x2=x >> 32;
  49. std::uint64_t y1=(std::uint32_t)y;
  50. std::uint64_t y2=y >> 32;
  51. std::uint64_t r3=x2*y2;
  52. std::uint64_t r2a=x1*y2;
  53. r3+=r2a>>32;
  54. std::uint64_t r2b=x2*y1;
  55. r3+=r2b>>32;
  56. std::uint64_t r1=x1*y1;
  57. std::uint64_t r2=(r1>>32)+(std::uint32_t)r2a+(std::uint32_t)r2b;
  58. r1=(r2<<32)+(std::uint32_t)r1;
  59. r3+=r2>>32;
  60. hi=r3;
  61. return r1;
  62. }
  63. #endif
  64. /* NOLINTNEXTLINE(readability-redundant-inline-specifier) */
  65. inline std::uint64_t mulx64(std::uint64_t x)noexcept
  66. {
  67. /* multiplier is 2^64/phi */
  68. std::uint64_t hi;
  69. std::uint64_t lo=umul128(x,0x9E3779B97F4A7C15ull,hi);
  70. return hi^lo;
  71. }
  72. } /* namespace detail */
  73. } /* namespace bloom */
  74. } /* namespace boost */
  75. #endif