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
5#ifndef BOOST_HASH_DETAIL_MULX_HPP
6#define BOOST_HASH_DETAIL_MULX_HPP
7
8#include <cstdint>
9#if defined(_MSC_VER)
10# include <intrin.h>
11#endif
12
13namespace boost
14{
15namespace hash_detail
16{
17
18#if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)
19
20__forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
21{
22 std::uint64_t r2;
23 std::uint64_t r = _umul128( x, y, &r2 );
24 return r ^ r2;
25}
26
27#elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
28
29__forceinline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
30{
31 std::uint64_t r = x * y;
32 std::uint64_t r2 = __umulh( x, y );
33 return r ^ r2;
34}
35
36#elif defined(__SIZEOF_INT128__)
37
38inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
39{
40 __uint128_t r = static_cast<__uint128_t>( x ) * y;
41 return static_cast<std::uint64_t>( r ) ^ static_cast<std::uint64_t>( r >> 64 );
42}
43
44#else
45
46inline std::uint64_t mulx( std::uint64_t x, std::uint64_t y )
47{
48 std::uint64_t x1 = static_cast<std::uint32_t>( x );
49 std::uint64_t x2 = x >> 32;
50
51 std::uint64_t y1 = static_cast<std::uint32_t>( y );
52 std::uint64_t y2 = y >> 32;
53
54 std::uint64_t r3 = x2 * y2;
55
56 std::uint64_t r2a = x1 * y2;
57
58 r3 += r2a >> 32;
59
60 std::uint64_t r2b = x2 * y1;
61
62 r3 += r2b >> 32;
63
64 std::uint64_t r1 = x1 * y1;
65
66 std::uint64_t r2 = (r1 >> 32) + static_cast<std::uint32_t>( r2a ) + static_cast<std::uint32_t>( r2b );
67
68 r1 = (r2 << 32) + static_cast<std::uint32_t>( r1 );
69 r3 += r2 >> 32;
70
71 return r1 ^ r3;
72}
73
74#endif
75
76} // namespace hash_detail
77} // namespace boost
78
79#endif // #ifndef BOOST_HASH_DETAIL_MULX_HPP
80

source code of boost/libs/container_hash/include/boost/container_hash/detail/mulx.hpp