MCKL
Monte Carlo Kernel Library
threefry_sse2_32.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/internal/threefry_sse2_32.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_THREEFRY_SSE2_32_HPP
33 #define MCKL_RANDOM_INTERNAL_THREEFRY_SSE2_32_HPP
34 
42 
43 MCKL_PUSH_GCC_WARNING("-Wignored-attributes")
44 
45 namespace mckl {
46 
47 namespace internal {
48 
49 template <typename T, std::size_t K, std::size_t Rounds, typename Constants>
51 {
52  public:
53  static void eval(
54  const void *plain, void *cipher, const std::array<T, K + 4> &par)
55  {
57  plain, cipher, par);
58  }
59 
60  template <typename ResultType>
61  static void eval(
62  Counter<T, K> &ctr, ResultType *r, const std::array<T, K + 4> &par)
63  {
65  ctr, r, par);
66  }
67 
68  template <typename ResultType>
69  static void eval(Counter<T, K> &ctr, std::size_t n, ResultType *r,
70  const std::array<T, K + 4> &par)
71  {
72  constexpr std::size_t S = K <= 8 ? 8 : K;
73  constexpr std::size_t N = sizeof(__m128i) * S / (sizeof(T) * K);
74  constexpr std::size_t R = sizeof(T) * K / sizeof(ResultType);
75 
76  while (n >= N) {
77  std::array<__m128i, S> s;
79  MCKL_INLINE_CALL transpose4x32_load_si128(s);
81  MCKL_INLINE_CALL transpose4x32_store_si128(s);
82  std::memcpy(r, s.data(), sizeof(T) * K * N);
83  n -= N;
84  r += N * R;
85  }
86 
87  alignas(MCKL_ALIGNMENT) std::array<ResultType, N * R> t;
89  ctr, n, t.data(), par);
90  std::memcpy(r, t.data(), sizeof(T) * K * n);
91  }
92 
93  private:
94  template <std::size_t N, std::size_t S>
95  static void round(std::array<__m128i, S> &, const std::array<T, K + 4> &,
96  std::false_type)
97  {
98  }
99 
100  template <std::size_t N, std::size_t S>
101  static void round(std::array<__m128i, S> &s,
102  const std::array<T, K + 4> &par, std::true_type)
103  {
105  }
106 
107  template <std::size_t N, std::size_t S>
108  MCKL_INLINE static void kbox(
109  std::array<__m128i, S> &s, const std::array<T, K + 4> &par)
110  {
111  kbox<N>(s, par,
112  std::integral_constant<bool, (N % 4 == 0 && N <= Rounds)>());
113  }
114 
115  template <std::size_t, std::size_t S>
116  static void kbox(std::array<__m128i, S> &, const std::array<T, K + 4> &,
117  std::false_type)
118  {
119  }
120 
121  template <std::size_t N>
122  static void kbox(std::array<__m128i, 8> &s,
123  const std::array<T, K + 4> &par, std::true_type)
124  {
125  std::array<__m128i, K> k;
126  set_key<N>(k, par);
127 
128  std::get<0>(s) = _mm_add_epi32(std::get<0>(s), std::get<0 % K>(k));
129  std::get<1>(s) = _mm_add_epi32(std::get<1>(s), std::get<1 % K>(k));
130  std::get<2>(s) = _mm_add_epi32(std::get<2>(s), std::get<2 % K>(k));
131  std::get<3>(s) = _mm_add_epi32(std::get<3>(s), std::get<3 % K>(k));
132  std::get<4>(s) = _mm_add_epi32(std::get<4>(s), std::get<4 % K>(k));
133  std::get<5>(s) = _mm_add_epi32(std::get<5>(s), std::get<5 % K>(k));
134  std::get<6>(s) = _mm_add_epi32(std::get<6>(s), std::get<6 % K>(k));
135  std::get<7>(s) = _mm_add_epi32(std::get<7>(s), std::get<7 % K>(k));
136  }
137 
138  template <std::size_t N>
139  static void kbox(std::array<__m128i, 16> &s,
140  const std::array<T, K + 4> &par, std::true_type)
141  {
142  std::array<__m128i, K> k;
143  set_key<N>(k, par);
144 
145  std::get<0x0>(s) =
146  _mm_add_epi32(std::get<0x0>(s), std::get<0x0 % K>(k));
147  std::get<0x1>(s) =
148  _mm_add_epi32(std::get<0x1>(s), std::get<0x1 % K>(k));
149  std::get<0x2>(s) =
150  _mm_add_epi32(std::get<0x2>(s), std::get<0x2 % K>(k));
151  std::get<0x3>(s) =
152  _mm_add_epi32(std::get<0x3>(s), std::get<0x3 % K>(k));
153  std::get<0x4>(s) =
154  _mm_add_epi32(std::get<0x4>(s), std::get<0x4 % K>(k));
155  std::get<0x5>(s) =
156  _mm_add_epi32(std::get<0x5>(s), std::get<0x5 % K>(k));
157  std::get<0x6>(s) =
158  _mm_add_epi32(std::get<0x6>(s), std::get<0x6 % K>(k));
159  std::get<0x7>(s) =
160  _mm_add_epi32(std::get<0x7>(s), std::get<0x7 % K>(k));
161  std::get<0x8>(s) =
162  _mm_add_epi32(std::get<0x8>(s), std::get<0x8 % K>(k));
163  std::get<0x9>(s) =
164  _mm_add_epi32(std::get<0x9>(s), std::get<0x9 % K>(k));
165  std::get<0xA>(s) =
166  _mm_add_epi32(std::get<0xA>(s), std::get<0xA % K>(k));
167  std::get<0xB>(s) =
168  _mm_add_epi32(std::get<0xB>(s), std::get<0xB % K>(k));
169  std::get<0xC>(s) =
170  _mm_add_epi32(std::get<0xC>(s), std::get<0xC % K>(k));
171  std::get<0xD>(s) =
172  _mm_add_epi32(std::get<0xD>(s), std::get<0xD % K>(k));
173  std::get<0xE>(s) =
174  _mm_add_epi32(std::get<0xE>(s), std::get<0xE % K>(k));
175  std::get<0xF>(s) =
176  _mm_add_epi32(std::get<0xF>(s), std::get<0xF % K>(k));
177  }
178 
179  template <std::size_t N, std::size_t S>
180  MCKL_INLINE static void rbox(std::array<__m128i, S> &s)
181  {
182  rbox<N>(s, std::integral_constant<bool, (N > 0 && N <= Rounds)>());
183  }
184 
185  template <std::size_t, std::size_t S>
186  static void rbox(std::array<__m128i, S> &, std::false_type)
187  {
188  }
189 
190  template <std::size_t N>
191  static void rbox(std::array<__m128i, 8> &s, std::true_type)
192  {
193  constexpr int L0 = Constants::rotate::value[0 % (K / 2)][(N - 1) % 8];
194  constexpr int L1 = Constants::rotate::value[1 % (K / 2)][(N - 1) % 8];
195  constexpr int L2 = Constants::rotate::value[2 % (K / 2)][(N - 1) % 8];
196  constexpr int L3 = Constants::rotate::value[3 % (K / 2)][(N - 1) % 8];
197  constexpr int R0 = 32 - L0;
198  constexpr int R1 = 32 - L1;
199  constexpr int R2 = 32 - L2;
200  constexpr int R3 = 32 - L3;
201 
202  std::get<0>(s) = _mm_add_epi32(std::get<0>(s), std::get<1>(s));
203  std::get<2>(s) = _mm_add_epi32(std::get<2>(s), std::get<3>(s));
204  std::get<4>(s) = _mm_add_epi32(std::get<4>(s), std::get<5>(s));
205  std::get<6>(s) = _mm_add_epi32(std::get<6>(s), std::get<7>(s));
206 
207  __m128i l0 = _mm_slli_epi32(std::get<1>(s), L0);
208  __m128i l1 = _mm_slli_epi32(std::get<3>(s), L1);
209  __m128i l2 = _mm_slli_epi32(std::get<5>(s), L2);
210  __m128i l3 = _mm_slli_epi32(std::get<7>(s), L3);
211 
212  __m128i r0 = _mm_srli_epi32(std::get<1>(s), R0);
213  __m128i r1 = _mm_srli_epi32(std::get<3>(s), R1);
214  __m128i r2 = _mm_srli_epi32(std::get<5>(s), R2);
215  __m128i r3 = _mm_srli_epi32(std::get<7>(s), R3);
216 
217  std::get<1>(s) = _mm_or_si128(l0, r0);
218  std::get<3>(s) = _mm_or_si128(l1, r1);
219  std::get<5>(s) = _mm_or_si128(l2, r2);
220  std::get<7>(s) = _mm_or_si128(l3, r3);
221 
222  std::get<1>(s) = _mm_xor_si128(std::get<0>(s), std::get<1>(s));
223  std::get<3>(s) = _mm_xor_si128(std::get<2>(s), std::get<3>(s));
224  std::get<5>(s) = _mm_xor_si128(std::get<4>(s), std::get<5>(s));
225  std::get<7>(s) = _mm_xor_si128(std::get<6>(s), std::get<7>(s));
226 
227  permute(s);
228  }
229 
230  template <std::size_t N>
231  static void rbox(std::array<__m128i, 16> &s, std::true_type)
232  {
233  constexpr int L0 = Constants::rotate::value[0 % (K / 2)][(N - 1) % 8];
234  constexpr int L1 = Constants::rotate::value[1 % (K / 2)][(N - 1) % 8];
235  constexpr int L2 = Constants::rotate::value[2 % (K / 2)][(N - 1) % 8];
236  constexpr int L3 = Constants::rotate::value[3 % (K / 2)][(N - 1) % 8];
237  constexpr int L4 = Constants::rotate::value[4 % (K / 2)][(N - 1) % 8];
238  constexpr int L5 = Constants::rotate::value[5 % (K / 2)][(N - 1) % 8];
239  constexpr int L6 = Constants::rotate::value[6 % (K / 2)][(N - 1) % 8];
240  constexpr int L7 = Constants::rotate::value[7 % (K / 2)][(N - 1) % 8];
241  constexpr int R0 = 32 - L0;
242  constexpr int R1 = 32 - L1;
243  constexpr int R2 = 32 - L2;
244  constexpr int R3 = 32 - L3;
245  constexpr int R4 = 32 - L4;
246  constexpr int R5 = 32 - L5;
247  constexpr int R6 = 32 - L6;
248  constexpr int R7 = 32 - L7;
249 
250  std::get<0x0>(s) = _mm_add_epi32(std::get<0x0>(s), std::get<0x1>(s));
251  std::get<0x2>(s) = _mm_add_epi32(std::get<0x2>(s), std::get<0x3>(s));
252  std::get<0x4>(s) = _mm_add_epi32(std::get<0x4>(s), std::get<0x5>(s));
253  std::get<0x6>(s) = _mm_add_epi32(std::get<0x6>(s), std::get<0x7>(s));
254  std::get<0x8>(s) = _mm_add_epi32(std::get<0x8>(s), std::get<0x9>(s));
255  std::get<0xA>(s) = _mm_add_epi32(std::get<0xA>(s), std::get<0xB>(s));
256  std::get<0xC>(s) = _mm_add_epi32(std::get<0xC>(s), std::get<0xD>(s));
257  std::get<0xE>(s) = _mm_add_epi32(std::get<0xE>(s), std::get<0xF>(s));
258 
259  __m128i l0 = _mm_slli_epi32(std::get<0x1>(s), L0);
260  __m128i l1 = _mm_slli_epi32(std::get<0x3>(s), L1);
261  __m128i l2 = _mm_slli_epi32(std::get<0x5>(s), L2);
262  __m128i l3 = _mm_slli_epi32(std::get<0x7>(s), L3);
263  __m128i l4 = _mm_slli_epi32(std::get<0x9>(s), L4);
264  __m128i l5 = _mm_slli_epi32(std::get<0xB>(s), L5);
265  __m128i l6 = _mm_slli_epi32(std::get<0xD>(s), L6);
266  __m128i l7 = _mm_slli_epi32(std::get<0xF>(s), L7);
267 
268  std::get<0x1>(s) = _mm_srli_epi32(std::get<0x1>(s), R0);
269  std::get<0x3>(s) = _mm_srli_epi32(std::get<0x3>(s), R1);
270  std::get<0x5>(s) = _mm_srli_epi32(std::get<0x5>(s), R2);
271  std::get<0x7>(s) = _mm_srli_epi32(std::get<0x7>(s), R3);
272  std::get<0x9>(s) = _mm_srli_epi32(std::get<0x9>(s), R4);
273  std::get<0xB>(s) = _mm_srli_epi32(std::get<0xB>(s), R5);
274  std::get<0xD>(s) = _mm_srli_epi32(std::get<0xD>(s), R6);
275  std::get<0xF>(s) = _mm_srli_epi32(std::get<0xF>(s), R7);
276 
277  std::get<0x1>(s) = _mm_or_si128(l0, std::get<0x1>(s));
278  std::get<0x3>(s) = _mm_or_si128(l1, std::get<0x3>(s));
279  std::get<0x5>(s) = _mm_or_si128(l2, std::get<0x5>(s));
280  std::get<0x7>(s) = _mm_or_si128(l3, std::get<0x7>(s));
281  std::get<0x9>(s) = _mm_or_si128(l4, std::get<0x9>(s));
282  std::get<0xB>(s) = _mm_or_si128(l5, std::get<0xB>(s));
283  std::get<0xD>(s) = _mm_or_si128(l6, std::get<0xD>(s));
284  std::get<0xF>(s) = _mm_or_si128(l7, std::get<0xF>(s));
285 
286  std::get<0x1>(s) = _mm_xor_si128(std::get<0x0>(s), std::get<0x1>(s));
287  std::get<0x3>(s) = _mm_xor_si128(std::get<0x2>(s), std::get<0x3>(s));
288  std::get<0x5>(s) = _mm_xor_si128(std::get<0x4>(s), std::get<0x5>(s));
289  std::get<0x7>(s) = _mm_xor_si128(std::get<0x6>(s), std::get<0x7>(s));
290  std::get<0x9>(s) = _mm_xor_si128(std::get<0x8>(s), std::get<0x9>(s));
291  std::get<0xB>(s) = _mm_xor_si128(std::get<0xA>(s), std::get<0xB>(s));
292  std::get<0xD>(s) = _mm_xor_si128(std::get<0xC>(s), std::get<0xD>(s));
293  std::get<0xF>(s) = _mm_xor_si128(std::get<0xE>(s), std::get<0xF>(s));
294 
295  permute(s);
296  }
297 
298  template <std::size_t N>
299  static void set_key(std::array<__m128i, 2> &k, const std::array<T, 6> &par)
300  {
301  std::get<0>(k) = _mm_set1_epi32(
302  static_cast<int>(ThreefryKBox<T, 2, N>::template key<0>(par)));
303  std::get<1>(k) = _mm_set1_epi32(
304  static_cast<int>(ThreefryKBox<T, 2, N>::template key<1>(par)));
305  }
306 
307  template <std::size_t N>
308  static void set_key(std::array<__m128i, 4> &k, const std::array<T, 8> &par)
309  {
310  std::get<0>(k) = _mm_set1_epi32(
311  static_cast<int>(ThreefryKBox<T, 4, N>::template key<0>(par)));
312  std::get<1>(k) = _mm_set1_epi32(
313  static_cast<int>(ThreefryKBox<T, 4, N>::template key<1>(par)));
314  std::get<2>(k) = _mm_set1_epi32(
315  static_cast<int>(ThreefryKBox<T, 4, N>::template key<2>(par)));
316  std::get<3>(k) = _mm_set1_epi32(
317  static_cast<int>(ThreefryKBox<T, 4, N>::template key<3>(par)));
318  }
319 
320  template <std::size_t N>
321  static void set_key(
322  std::array<__m128i, 8> &k, const std::array<T, 12> &par)
323  {
324  std::get<0>(k) = _mm_set1_epi32(
325  static_cast<int>(ThreefryKBox<T, 8, N>::template key<0>(par)));
326  std::get<1>(k) = _mm_set1_epi32(
327  static_cast<int>(ThreefryKBox<T, 8, N>::template key<1>(par)));
328  std::get<2>(k) = _mm_set1_epi32(
329  static_cast<int>(ThreefryKBox<T, 8, N>::template key<2>(par)));
330  std::get<3>(k) = _mm_set1_epi32(
331  static_cast<int>(ThreefryKBox<T, 8, N>::template key<3>(par)));
332  std::get<4>(k) = _mm_set1_epi32(
333  static_cast<int>(ThreefryKBox<T, 8, N>::template key<4>(par)));
334  std::get<5>(k) = _mm_set1_epi32(
335  static_cast<int>(ThreefryKBox<T, 8, N>::template key<5>(par)));
336  std::get<6>(k) = _mm_set1_epi32(
337  static_cast<int>(ThreefryKBox<T, 8, N>::template key<6>(par)));
338  std::get<7>(k) = _mm_set1_epi32(
339  static_cast<int>(ThreefryKBox<T, 8, N>::template key<7>(par)));
340  }
341 
342  template <std::size_t N>
343  static void set_key(
344  std::array<__m128i, 16> &k, const std::array<T, 20> &par)
345  {
346  std::get<0x0>(k) = _mm_set1_epi32(
347  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x0>(par)));
348  std::get<0x1>(k) = _mm_set1_epi32(
349  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x1>(par)));
350  std::get<0x2>(k) = _mm_set1_epi32(
351  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x2>(par)));
352  std::get<0x3>(k) = _mm_set1_epi32(
353  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x3>(par)));
354  std::get<0x4>(k) = _mm_set1_epi32(
355  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x4>(par)));
356  std::get<0x5>(k) = _mm_set1_epi32(
357  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x5>(par)));
358  std::get<0x6>(k) = _mm_set1_epi32(
359  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x6>(par)));
360  std::get<0x7>(k) = _mm_set1_epi32(
361  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x7>(par)));
362  std::get<0x8>(k) = _mm_set1_epi32(
363  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x8>(par)));
364  std::get<0x9>(k) = _mm_set1_epi32(
365  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0x9>(par)));
366  std::get<0xA>(k) = _mm_set1_epi32(
367  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0xA>(par)));
368  std::get<0xB>(k) = _mm_set1_epi32(
369  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0xB>(par)));
370  std::get<0xC>(k) = _mm_set1_epi32(
371  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0xC>(par)));
372  std::get<0xD>(k) = _mm_set1_epi32(
373  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0xD>(par)));
374  std::get<0xE>(k) = _mm_set1_epi32(
375  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0xE>(par)));
376  std::get<0xF>(k) = _mm_set1_epi32(
377  static_cast<int>(ThreefryKBox<T, 16, N>::template key<0xF>(par)));
378  }
379 
380  template <std::size_t S>
381  static void permute(std::array<__m128i, S> &s)
382  {
383  permute<0>(s, std::integral_constant<bool, 0 < S / K>());
384  }
385 
386  template <std::size_t, std::size_t S>
387  static void permute(std::array<__m128i, S> &, std::false_type)
388  {
389  }
390 
391  template <std::size_t I, std::size_t S>
392  static void permute(std::array<__m128i, S> &s, std::true_type)
393  {
395  permute<I + 1>(s, std::integral_constant<bool, I + 1 < S / K>());
396  }
397 }; // class ThreefryGeneratorSSE2Impl32
398 
399 template <typename T>
402 {
403 }; // class ThreefryGeneratorSSE2Impl32
404 
405 template <typename T>
408 {
409 }; // class ThreefryGeneratorSSE2Impl32
410 
411 } // namespace internal
412 
413 } // namespace mckl
414 
416 
417 #endif // MCKL_RANDOM_INTERNAL_THREEFRY_SSE2_32_HPP
#define MCKL_PUSH_GCC_WARNING(warning)
Definition: compiler.h:78
void increment_si128(std::array< T, K > &ctr, std::array< __m128i, S > &s, std::false_type)
void round(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:310
#define MCKL_INLINE_CALL
Definition: intel.h:142
static void eval(Counter< T, K > &ctr, std::size_t n, ResultType *r, const std::array< T, K+4 > &par)
static void eval(const void *plain, void *cipher, const std::array< T, K+4 > &par)
typename internal::CounterImpl< T, K >::type Counter
A counter type with the same width as std::array<T, K> but with possibly fewer elements.
Definition: increment.hpp:104
static void eval(Counter< T, K > &ctr, ResultType *r, const std::array< T, K+4 > &par)
#define MCKL_RANDOM_INTERNAL_THREEFRY_UNROLL_ROUND(N, s, par)
Default Threefry constants.
Definition: mcmc.hpp:40
#define MCKL_ALIGNMENT
The default alignment for scalar type.
Definition: config.h:187
#define MCKL_INLINE
Definition: clang.h:147
#define MCKL_POP_GCC_WARNING
Definition: compiler.h:79