MCKL
Monte Carlo Kernel Library
philox_avx2_4x32.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/internal/philox_avx2_4x32.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef MCKL_RANDOM_INTERNAL_PHILOX_AVX2_4X32_HPP
33 #define MCKL_RANDOM_INTERNAL_PHILOX_AVX2_4X32_HPP
34 
40 
41 MCKL_PUSH_GCC_WARNING("-Wignored-attributes")
42 
43 namespace mckl {
44 
45 namespace internal {
46 
47 template <typename T, typename Constants>
49 {
50  static_assert(std::numeric_limits<T>::digits == 32,
51  "**Philox4x32GeneratorAVX2Impl** used with T other than a 32-bit "
52  "unsigned integers");
53 
54  static constexpr std::size_t K = 4;
55  static constexpr std::size_t Rounds = 10;
56 
57  public:
58  static void eval(
59  const void *plain, void *cipher, const std::array<T, K / 2> &key)
60  {
62  }
63 
64  template <typename ResultType>
65  static void eval(std::array<std::uint64_t, 2> &ctr, ResultType *r,
66  const std::array<T, K / 2> &key)
67  {
69  }
70 
71  template <typename ResultType>
72  static void eval(std::array<std::uint64_t, 2> &ctr, std::size_t n,
73  ResultType *r, const std::array<T, K / 2> &key)
74  {
75  constexpr std::size_t R = sizeof(T) * K / sizeof(ResultType);
76 
77  const std::size_t n0 =
78  static_cast<std::size_t>(std::min(static_cast<std::uint64_t>(n),
79  std::numeric_limits<std::uint64_t>::max() - ctr.front()));
80 
81  eval_kernel(ctr, n0, r, key);
82  n -= n0;
83  r += n0 * R;
84 
85  if (n != 0) {
86  eval(ctr, r, key);
87  n -= 1;
88  r += R;
89  }
90 
91  eval_kernel(ctr, n, r, key);
92  }
93 
94  private:
95  template <typename ResultType>
96  static void eval_kernel(std::array<std::uint64_t, 2> &ctr, std::size_t n,
97  ResultType *r, const std::array<T, K / 2> &key)
98  {
99 #if MCKL_USE_ASM_LIBRARY
100  constexpr T m0 = Constants::multiplier::value[0];
101  constexpr T m1 = Constants::multiplier::value[1];
102  constexpr T w0 = Constants::weyl::value[0];
103  constexpr T w1 = Constants::weyl::value[1];
104 
105  const T mwk[12] = {m0, 0, m1, 0, 0, w0, 0, w1, 0, std::get<0>(key), 0,
106  std::get<1>(key)};
107  mckl_philox4x32_avx2_kernel(ctr.data(), n, r, mwk);
108 #else // MCKL_USE_ASM_LIBRARY
109  constexpr std::size_t S = 8;
110  constexpr std::size_t N = sizeof(__m256i) * S / (sizeof(T) * K);
111 
112  const int k0 = static_cast<int>(std::get<0>(key));
113  const int k1 = static_cast<int>(std::get<1>(key));
114  const __m256i ymmk0 = _mm256_set_epi32(k1, 0, k0, 0, k1, 0, k0, 0);
115 
116  __m256i ymmc =
117  _mm256_set_epi64x(static_cast<MCKL_INT64>(std::get<1>(ctr)),
118  static_cast<MCKL_INT64>(std::get<0>(ctr)),
119  static_cast<MCKL_INT64>(std::get<1>(ctr)),
120  static_cast<MCKL_INT64>(std::get<0>(ctr)));
121  ctr.front() += n;
122 
123  __m256i *rptr = reinterpret_cast<__m256i *>(r);
124  while (n != 0) {
125  __m256i ymm0 =
126  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x02, 0, 0x01));
127  __m256i ymm1 =
128  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x04, 0, 0x03));
129  __m256i ymm2 =
130  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x06, 0, 0x05));
131  __m256i ymm3 =
132  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x08, 0, 0x07));
133  __m256i ymm4 =
134  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x0A, 0, 0x09));
135  __m256i ymm5 =
136  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x0C, 0, 0x0B));
137  __m256i ymm6 =
138  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x0E, 0, 0x0D));
139  __m256i ymm7 =
140  _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x10, 0, 0x0F));
141  ymmc = _mm256_add_epi64(ymmc, _mm256_set_epi64x(0, 0x10, 0, 0x10));
142 
143  ymm0 = _mm256_shuffle_epi32(ymm0, 0xC6);
144  ymm1 = _mm256_shuffle_epi32(ymm1, 0xC6);
145  ymm2 = _mm256_shuffle_epi32(ymm2, 0xC6);
146  ymm3 = _mm256_shuffle_epi32(ymm3, 0xC6);
147  ymm4 = _mm256_shuffle_epi32(ymm4, 0xC6);
148  ymm5 = _mm256_shuffle_epi32(ymm5, 0xC6);
149  ymm6 = _mm256_shuffle_epi32(ymm6, 0xC6);
150  ymm7 = _mm256_shuffle_epi32(ymm7, 0xC6);
151 
162 
163  if (n >= N) {
164  n -= N;
165  _mm256_storeu_si256(rptr++, ymm0);
166  _mm256_storeu_si256(rptr++, ymm1);
167  _mm256_storeu_si256(rptr++, ymm2);
168  _mm256_storeu_si256(rptr++, ymm3);
169  _mm256_storeu_si256(rptr++, ymm4);
170  _mm256_storeu_si256(rptr++, ymm5);
171  _mm256_storeu_si256(rptr++, ymm6);
172  _mm256_storeu_si256(rptr++, ymm7);
173  } else {
174  std::array<__m256i, S> s;
175  std::get<0>(s) = ymm0;
176  std::get<1>(s) = ymm1;
177  std::get<2>(s) = ymm2;
178  std::get<3>(s) = ymm3;
179  std::get<4>(s) = ymm4;
180  std::get<5>(s) = ymm5;
181  std::get<6>(s) = ymm6;
182  std::get<7>(s) = ymm7;
183  std::memcpy(rptr, s.data(), n * sizeof(T) * K);
184  break;
185  }
186  }
187 #endif // MCKL_USE_ASM_LIBRARY
188  }
189 }; // class Philox4x32GeneratorAVX2Impl
190 
191 } // namespace internal
192 
193 } // namespace mckl
194 
196 
197 #endif // MCKL_RANDOM_INTERNAL_PHILOX_AVX2_4X32_HPP
#define MCKL_PUSH_GCC_WARNING(warning)
Definition: compiler.h:78
static void eval(std::array< std::uint64_t, 2 > &ctr, std::size_t n, ResultType *r, const std::array< T, K/2 > &key)
static void eval(std::array< std::uint64_t, 2 > &ctr, ResultType *r, const std::array< T, K/2 > &key)
#define MCKL_RANDOM_INTERNAL_PHILOX_AVX2_32_RBOX(K, N, imm8)
void mckl_philox4x32_avx2_kernel(uint64_t *, size_t, void *, const void *)
Definition: mcmc.hpp:40
static void eval(const void *plain, void *cipher, const std::array< T, K/2 > &key)
#define MCKL_POP_GCC_WARNING
Definition: compiler.h:79