MCKL
Monte Carlo Kernel Library
u01_avx2.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/internal/u01_avx2.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_U01_AVX2_HPP
33 #define MCKL_RANDOM_INTERNAL_U01_AVX2_HPP
34 
37 
38 MCKL_PUSH_GCC_WARNING("-Wignored-attributes")
39 
40 #define MCKL_RANDOM_INTERNAL_U01_AVX2_LOADU_SI256(u) \
41  const __m256i *uptr = reinterpret_cast<const __m256i *>(u); \
42  __m256i ymm0 = _mm256_loadu_si256(uptr++); \
43  __m256i ymm1 = _mm256_loadu_si256(uptr++); \
44  __m256i ymm2 = _mm256_loadu_si256(uptr++); \
45  __m256i ymm3 = _mm256_loadu_si256(uptr++); \
46  __m256i ymm4 = _mm256_loadu_si256(uptr++); \
47  __m256i ymm5 = _mm256_loadu_si256(uptr++); \
48  __m256i ymm6 = _mm256_loadu_si256(uptr++); \
49  __m256i ymm7 = _mm256_loadu_si256(uptr++);
50 
51 #define MCKL_RANDOM_INTERNAL_U01_AVX2_LOADU_SI256_CVTEPU32_EPI64(u) \
52  const __m128i *uptr = reinterpret_cast<const __m128i *>(u); \
53  __m256i ymm0 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++)); \
54  __m256i ymm1 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++)); \
55  __m256i ymm2 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++)); \
56  __m256i ymm3 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++)); \
57  __m256i ymm4 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++)); \
58  __m256i ymm5 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++)); \
59  __m256i ymm6 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++)); \
60  __m256i ymm7 = _mm256_cvtepu32_epi64(_mm_loadu_si128(uptr++));
61 
62 #define MCKL_RANDOM_INTERNAL_U01_AVX2_STOREU_PS(r) \
63  _mm256_storeu_ps(r + 0x00, _mm256_castsi256_ps(ymm0)); \
64  _mm256_storeu_ps(r + 0x08, _mm256_castsi256_ps(ymm1)); \
65  _mm256_storeu_ps(r + 0x10, _mm256_castsi256_ps(ymm2)); \
66  _mm256_storeu_ps(r + 0x18, _mm256_castsi256_ps(ymm3)); \
67  _mm256_storeu_ps(r + 0x20, _mm256_castsi256_ps(ymm4)); \
68  _mm256_storeu_ps(r + 0x28, _mm256_castsi256_ps(ymm5)); \
69  _mm256_storeu_ps(r + 0x30, _mm256_castsi256_ps(ymm6)); \
70  _mm256_storeu_ps(r + 0x38, _mm256_castsi256_ps(ymm7));
71 
72 #define MCKL_RANDOM_INTERNAL_U01_AVX2_STOREU_PD(r) \
73  _mm256_storeu_pd(r + 0x00, _mm256_castsi256_pd(ymm0)); \
74  _mm256_storeu_pd(r + 0x04, _mm256_castsi256_pd(ymm1)); \
75  _mm256_storeu_pd(r + 0x08, _mm256_castsi256_pd(ymm2)); \
76  _mm256_storeu_pd(r + 0x0C, _mm256_castsi256_pd(ymm3)); \
77  _mm256_storeu_pd(r + 0x10, _mm256_castsi256_pd(ymm4)); \
78  _mm256_storeu_pd(r + 0x14, _mm256_castsi256_pd(ymm5)); \
79  _mm256_storeu_pd(r + 0x18, _mm256_castsi256_pd(ymm6)); \
80  _mm256_storeu_pd(r + 0x1C, _mm256_castsi256_pd(ymm7));
81 
82 #define MCKL_RANDOM_INTERNAL_U01_AVX2_AND1ADD_EPI32 \
83  const __m256i mask = _mm256_set1_epi32(1); \
84  ymm0 = _mm256_add_epi32(ymm0, _mm256_and_si256(ymm0, mask)); \
85  ymm1 = _mm256_add_epi32(ymm1, _mm256_and_si256(ymm1, mask)); \
86  ymm2 = _mm256_add_epi32(ymm2, _mm256_and_si256(ymm2, mask)); \
87  ymm3 = _mm256_add_epi32(ymm3, _mm256_and_si256(ymm3, mask)); \
88  ymm4 = _mm256_add_epi32(ymm4, _mm256_and_si256(ymm4, mask)); \
89  ymm5 = _mm256_add_epi32(ymm5, _mm256_and_si256(ymm5, mask)); \
90  ymm6 = _mm256_add_epi32(ymm6, _mm256_and_si256(ymm6, mask)); \
91  ymm7 = _mm256_add_epi32(ymm7, _mm256_and_si256(ymm7, mask));
92 
93 #define MCKL_RANDOM_INTERNAL_U01_AVX2_AND1ADD_EPI64 \
94  const __m256i mask = _mm256_set1_epi64x(1); \
95  ymm0 = _mm256_add_epi64(ymm0, _mm256_and_si256(ymm0, mask)); \
96  ymm1 = _mm256_add_epi64(ymm1, _mm256_and_si256(ymm1, mask)); \
97  ymm2 = _mm256_add_epi64(ymm2, _mm256_and_si256(ymm2, mask)); \
98  ymm3 = _mm256_add_epi64(ymm3, _mm256_and_si256(ymm3, mask)); \
99  ymm4 = _mm256_add_epi64(ymm4, _mm256_and_si256(ymm4, mask)); \
100  ymm5 = _mm256_add_epi64(ymm5, _mm256_and_si256(ymm5, mask)); \
101  ymm6 = _mm256_add_epi64(ymm6, _mm256_and_si256(ymm6, mask)); \
102  ymm7 = _mm256_add_epi64(ymm7, _mm256_and_si256(ymm7, mask));
103 
104 #define MCKL_RANDOM_INTERNAL_U01_AVX2_SLLI_EPI32(imm8) \
105  ymm0 = _mm256_slli_epi32(ymm0, imm8); \
106  ymm1 = _mm256_slli_epi32(ymm1, imm8); \
107  ymm2 = _mm256_slli_epi32(ymm2, imm8); \
108  ymm3 = _mm256_slli_epi32(ymm3, imm8); \
109  ymm4 = _mm256_slli_epi32(ymm4, imm8); \
110  ymm5 = _mm256_slli_epi32(ymm5, imm8); \
111  ymm6 = _mm256_slli_epi32(ymm6, imm8); \
112  ymm7 = _mm256_slli_epi32(ymm7, imm8);
113 
114 #define MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI32(imm8) \
115  ymm0 = _mm256_srli_epi32(ymm0, imm8); \
116  ymm1 = _mm256_srli_epi32(ymm1, imm8); \
117  ymm2 = _mm256_srli_epi32(ymm2, imm8); \
118  ymm3 = _mm256_srli_epi32(ymm3, imm8); \
119  ymm4 = _mm256_srli_epi32(ymm4, imm8); \
120  ymm5 = _mm256_srli_epi32(ymm5, imm8); \
121  ymm6 = _mm256_srli_epi32(ymm6, imm8); \
122  ymm7 = _mm256_srli_epi32(ymm7, imm8);
123 
124 #define MCKL_RANDOM_INTERNAL_U01_AVX2_SLLI_EPI64(imm8) \
125  ymm0 = _mm256_slli_epi64(ymm0, imm8); \
126  ymm1 = _mm256_slli_epi64(ymm1, imm8); \
127  ymm2 = _mm256_slli_epi64(ymm2, imm8); \
128  ymm3 = _mm256_slli_epi64(ymm3, imm8); \
129  ymm4 = _mm256_slli_epi64(ymm4, imm8); \
130  ymm5 = _mm256_slli_epi64(ymm5, imm8); \
131  ymm6 = _mm256_slli_epi64(ymm6, imm8); \
132  ymm7 = _mm256_slli_epi64(ymm7, imm8);
133 
134 #define MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI64(imm8) \
135  ymm0 = _mm256_srli_epi64(ymm0, imm8); \
136  ymm1 = _mm256_srli_epi64(ymm1, imm8); \
137  ymm2 = _mm256_srli_epi64(ymm2, imm8); \
138  ymm3 = _mm256_srli_epi64(ymm3, imm8); \
139  ymm4 = _mm256_srli_epi64(ymm4, imm8); \
140  ymm5 = _mm256_srli_epi64(ymm5, imm8); \
141  ymm6 = _mm256_srli_epi64(ymm6, imm8); \
142  ymm7 = _mm256_srli_epi64(ymm7, imm8);
143 
144 #define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU32_PS_31 \
145  ymm0 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm0)); \
146  ymm1 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm1)); \
147  ymm2 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm2)); \
148  ymm3 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm3)); \
149  ymm4 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm4)); \
150  ymm5 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm5)); \
151  ymm6 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm6)); \
152  ymm7 = _mm256_castps_si256(_mm256_cvtepi32_ps(ymm7));
153 
154 #if MCKL_USE_FMA
155 
156 #define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU32_PS \
157  const __m256 c = _mm256_set1_ps(Pow2<float, 23>::value); \
158  const __m256 d = _mm256_set1_ps(Pow2<float, 16>::value); \
159  const __m256i l = _mm256_set1_epi32(static_cast<int>(0xFFFF)); \
160  __m256i zmm0 = _mm256_and_si256(ymm0, l); \
161  __m256i zmm1 = _mm256_and_si256(ymm1, l); \
162  __m256i zmm2 = _mm256_and_si256(ymm2, l); \
163  __m256i zmm3 = _mm256_and_si256(ymm3, l); \
164  __m256i zmm4 = _mm256_and_si256(ymm4, l); \
165  __m256i zmm5 = _mm256_and_si256(ymm5, l); \
166  __m256i zmm6 = _mm256_and_si256(ymm6, l); \
167  __m256i zmm7 = _mm256_and_si256(ymm7, l); \
168  MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI32(16); \
169  ymm0 = _mm256_add_epi32(ymm0, _mm256_castps_si256(c)); \
170  ymm1 = _mm256_add_epi32(ymm1, _mm256_castps_si256(c)); \
171  ymm2 = _mm256_add_epi32(ymm2, _mm256_castps_si256(c)); \
172  ymm3 = _mm256_add_epi32(ymm3, _mm256_castps_si256(c)); \
173  ymm4 = _mm256_add_epi32(ymm4, _mm256_castps_si256(c)); \
174  ymm5 = _mm256_add_epi32(ymm5, _mm256_castps_si256(c)); \
175  ymm6 = _mm256_add_epi32(ymm6, _mm256_castps_si256(c)); \
176  ymm7 = _mm256_add_epi32(ymm7, _mm256_castps_si256(c)); \
177  zmm0 = _mm256_add_epi32(zmm0, _mm256_castps_si256(c)); \
178  zmm1 = _mm256_add_epi32(zmm1, _mm256_castps_si256(c)); \
179  zmm2 = _mm256_add_epi32(zmm2, _mm256_castps_si256(c)); \
180  zmm3 = _mm256_add_epi32(zmm3, _mm256_castps_si256(c)); \
181  zmm4 = _mm256_add_epi32(zmm4, _mm256_castps_si256(c)); \
182  zmm5 = _mm256_add_epi32(zmm5, _mm256_castps_si256(c)); \
183  zmm6 = _mm256_add_epi32(zmm6, _mm256_castps_si256(c)); \
184  zmm7 = _mm256_add_epi32(zmm7, _mm256_castps_si256(c)); \
185  ymm0 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm0), c)); \
186  ymm1 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm1), c)); \
187  ymm2 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm2), c)); \
188  ymm3 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm3), c)); \
189  ymm4 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm4), c)); \
190  ymm5 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm5), c)); \
191  ymm6 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm6), c)); \
192  ymm7 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm7), c)); \
193  zmm0 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm0), c)); \
194  zmm1 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm1), c)); \
195  zmm2 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm2), c)); \
196  zmm3 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm3), c)); \
197  zmm4 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm4), c)); \
198  zmm5 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm5), c)); \
199  zmm6 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm6), c)); \
200  zmm7 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm7), c)); \
201  ymm0 = _mm256_castps_si256(_mm256_fmadd_ps( \
202  _mm256_castsi256_ps(ymm0), d, _mm256_castsi256_ps(zmm0))); \
203  ymm1 = _mm256_castps_si256(_mm256_fmadd_ps( \
204  _mm256_castsi256_ps(ymm1), d, _mm256_castsi256_ps(zmm1))); \
205  ymm2 = _mm256_castps_si256(_mm256_fmadd_ps( \
206  _mm256_castsi256_ps(ymm2), d, _mm256_castsi256_ps(zmm2))); \
207  ymm3 = _mm256_castps_si256(_mm256_fmadd_ps( \
208  _mm256_castsi256_ps(ymm3), d, _mm256_castsi256_ps(zmm3))); \
209  ymm4 = _mm256_castps_si256(_mm256_fmadd_ps( \
210  _mm256_castsi256_ps(ymm4), d, _mm256_castsi256_ps(zmm4))); \
211  ymm5 = _mm256_castps_si256(_mm256_fmadd_ps( \
212  _mm256_castsi256_ps(ymm5), d, _mm256_castsi256_ps(zmm5))); \
213  ymm6 = _mm256_castps_si256(_mm256_fmadd_ps( \
214  _mm256_castsi256_ps(ymm6), d, _mm256_castsi256_ps(zmm6))); \
215  ymm7 = _mm256_castps_si256(_mm256_fmadd_ps( \
216  _mm256_castsi256_ps(ymm7), d, _mm256_castsi256_ps(zmm7)));
217 
218 #else // MCKL_USE_FMA
219 
220 #define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU32_PS \
221  const __m256 c = _mm256_set1_ps(Pow2<float, 23>::value); \
222  const __m256 d = _mm256_set1_ps(Pow2<float, 16>::value); \
223  const __m256i l = _mm256_set1_epi32(static_cast<MCKL_INT64>(0xFFFF)); \
224  __m256i zmm0 = _mm256_and_si256(ymm0, l); \
225  __m256i zmm1 = _mm256_and_si256(ymm1, l); \
226  __m256i zmm2 = _mm256_and_si256(ymm2, l); \
227  __m256i zmm3 = _mm256_and_si256(ymm3, l); \
228  __m256i zmm4 = _mm256_and_si256(ymm4, l); \
229  __m256i zmm5 = _mm256_and_si256(ymm5, l); \
230  __m256i zmm6 = _mm256_and_si256(ymm6, l); \
231  __m256i zmm7 = _mm256_and_si256(ymm7, l); \
232  MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI32(16); \
233  ymm0 = _mm256_add_epi32(ymm0, _mm256_castps_si256(c)); \
234  ymm1 = _mm256_add_epi32(ymm1, _mm256_castps_si256(c)); \
235  ymm2 = _mm256_add_epi32(ymm2, _mm256_castps_si256(c)); \
236  ymm3 = _mm256_add_epi32(ymm3, _mm256_castps_si256(c)); \
237  ymm4 = _mm256_add_epi32(ymm4, _mm256_castps_si256(c)); \
238  ymm5 = _mm256_add_epi32(ymm5, _mm256_castps_si256(c)); \
239  ymm6 = _mm256_add_epi32(ymm6, _mm256_castps_si256(c)); \
240  ymm7 = _mm256_add_epi32(ymm7, _mm256_castps_si256(c)); \
241  zmm0 = _mm256_add_epi32(zmm0, _mm256_castps_si256(c)); \
242  zmm1 = _mm256_add_epi32(zmm1, _mm256_castps_si256(c)); \
243  zmm2 = _mm256_add_epi32(zmm2, _mm256_castps_si256(c)); \
244  zmm3 = _mm256_add_epi32(zmm3, _mm256_castps_si256(c)); \
245  zmm4 = _mm256_add_epi32(zmm4, _mm256_castps_si256(c)); \
246  zmm5 = _mm256_add_epi32(zmm5, _mm256_castps_si256(c)); \
247  zmm6 = _mm256_add_epi32(zmm6, _mm256_castps_si256(c)); \
248  zmm7 = _mm256_add_epi32(zmm7, _mm256_castps_si256(c)); \
249  ymm0 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm0), c)); \
250  ymm1 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm1), c)); \
251  ymm2 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm2), c)); \
252  ymm3 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm3), c)); \
253  ymm4 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm4), c)); \
254  ymm5 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm5), c)); \
255  ymm6 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm6), c)); \
256  ymm7 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(ymm7), c)); \
257  zmm0 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm0), c)); \
258  zmm1 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm1), c)); \
259  zmm2 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm2), c)); \
260  zmm3 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm3), c)); \
261  zmm4 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm4), c)); \
262  zmm5 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm5), c)); \
263  zmm6 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm6), c)); \
264  zmm7 = _mm256_castps_si256(_mm256_sub_ps(_mm256_castsi256_ps(zmm7), c)); \
265  ymm0 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm0), d)); \
266  ymm1 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm1), d)); \
267  ymm2 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm2), d)); \
268  ymm3 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm3), d)); \
269  ymm4 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm4), d)); \
270  ymm5 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm5), d)); \
271  ymm6 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm6), d)); \
272  ymm7 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm7), d)); \
273  ymm0 = _mm256_castps_si256( \
274  _mm256_add_ps(_mm256_castsi256_ps(ymm0), _mm256_castsi256_ps(zmm0))); \
275  ymm1 = _mm256_castps_si256( \
276  _mm256_add_ps(_mm256_castsi256_ps(ymm1), _mm256_castsi256_ps(zmm1))); \
277  ymm2 = _mm256_castps_si256( \
278  _mm256_add_ps(_mm256_castsi256_ps(ymm2), _mm256_castsi256_ps(zmm2))); \
279  ymm3 = _mm256_castps_si256( \
280  _mm256_add_ps(_mm256_castsi256_ps(ymm3), _mm256_castsi256_ps(zmm3))); \
281  ymm4 = _mm256_castps_si256( \
282  _mm256_add_ps(_mm256_castsi256_ps(ymm4), _mm256_castsi256_ps(zmm4))); \
283  ymm5 = _mm256_castps_si256( \
284  _mm256_add_ps(_mm256_castsi256_ps(ymm5), _mm256_castsi256_ps(zmm5))); \
285  ymm6 = _mm256_castps_si256( \
286  _mm256_add_ps(_mm256_castsi256_ps(ymm6), _mm256_castsi256_ps(zmm6))); \
287  ymm7 = _mm256_castps_si256( \
288  _mm256_add_ps(_mm256_castsi256_ps(ymm7), _mm256_castsi256_ps(zmm7)));
289 
290 #endif // // MCKL_USE_FMA
291 
292 #define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU64_PD_52 \
293  const __m256d c = _mm256_set1_pd(Pow2<double, 52>::value); \
294  ymm0 = _mm256_add_epi64(ymm0, _mm256_castpd_si256(c)); \
295  ymm1 = _mm256_add_epi64(ymm1, _mm256_castpd_si256(c)); \
296  ymm2 = _mm256_add_epi64(ymm2, _mm256_castpd_si256(c)); \
297  ymm3 = _mm256_add_epi64(ymm3, _mm256_castpd_si256(c)); \
298  ymm4 = _mm256_add_epi64(ymm4, _mm256_castpd_si256(c)); \
299  ymm5 = _mm256_add_epi64(ymm5, _mm256_castpd_si256(c)); \
300  ymm6 = _mm256_add_epi64(ymm6, _mm256_castpd_si256(c)); \
301  ymm7 = _mm256_add_epi64(ymm7, _mm256_castpd_si256(c)); \
302  ymm0 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm0), c)); \
303  ymm1 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm1), c)); \
304  ymm2 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm2), c)); \
305  ymm3 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm3), c)); \
306  ymm4 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm4), c)); \
307  ymm5 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm5), c)); \
308  ymm6 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm6), c)); \
309  ymm7 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm7), c));
310 
311 #if MCKL_USE_FMA
312 
313 #define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU64_PD \
314  const __m256d c = _mm256_set1_pd(Pow2<double, 52>::value); \
315  const __m256d d = _mm256_set1_pd(Pow2<double, 32>::value); \
316  const __m256i l = \
317  _mm256_set1_epi64x(static_cast<MCKL_INT64>(0xFFFFFFFF)); \
318  __m256i zmm0 = _mm256_and_si256(ymm0, l); \
319  __m256i zmm1 = _mm256_and_si256(ymm1, l); \
320  __m256i zmm2 = _mm256_and_si256(ymm2, l); \
321  __m256i zmm3 = _mm256_and_si256(ymm3, l); \
322  __m256i zmm4 = _mm256_and_si256(ymm4, l); \
323  __m256i zmm5 = _mm256_and_si256(ymm5, l); \
324  __m256i zmm6 = _mm256_and_si256(ymm6, l); \
325  __m256i zmm7 = _mm256_and_si256(ymm7, l); \
326  MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI64(32); \
327  ymm0 = _mm256_add_epi64(ymm0, _mm256_castpd_si256(c)); \
328  ymm1 = _mm256_add_epi64(ymm1, _mm256_castpd_si256(c)); \
329  ymm2 = _mm256_add_epi64(ymm2, _mm256_castpd_si256(c)); \
330  ymm3 = _mm256_add_epi64(ymm3, _mm256_castpd_si256(c)); \
331  ymm4 = _mm256_add_epi64(ymm4, _mm256_castpd_si256(c)); \
332  ymm5 = _mm256_add_epi64(ymm5, _mm256_castpd_si256(c)); \
333  ymm6 = _mm256_add_epi64(ymm6, _mm256_castpd_si256(c)); \
334  ymm7 = _mm256_add_epi64(ymm7, _mm256_castpd_si256(c)); \
335  zmm0 = _mm256_add_epi64(zmm0, _mm256_castpd_si256(c)); \
336  zmm1 = _mm256_add_epi64(zmm1, _mm256_castpd_si256(c)); \
337  zmm2 = _mm256_add_epi64(zmm2, _mm256_castpd_si256(c)); \
338  zmm3 = _mm256_add_epi64(zmm3, _mm256_castpd_si256(c)); \
339  zmm4 = _mm256_add_epi64(zmm4, _mm256_castpd_si256(c)); \
340  zmm5 = _mm256_add_epi64(zmm5, _mm256_castpd_si256(c)); \
341  zmm6 = _mm256_add_epi64(zmm6, _mm256_castpd_si256(c)); \
342  zmm7 = _mm256_add_epi64(zmm7, _mm256_castpd_si256(c)); \
343  ymm0 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm0), c)); \
344  ymm1 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm1), c)); \
345  ymm2 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm2), c)); \
346  ymm3 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm3), c)); \
347  ymm4 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm4), c)); \
348  ymm5 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm5), c)); \
349  ymm6 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm6), c)); \
350  ymm7 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm7), c)); \
351  zmm0 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm0), c)); \
352  zmm1 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm1), c)); \
353  zmm2 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm2), c)); \
354  zmm3 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm3), c)); \
355  zmm4 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm4), c)); \
356  zmm5 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm5), c)); \
357  zmm6 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm6), c)); \
358  zmm7 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm7), c)); \
359  ymm0 = _mm256_castpd_si256(_mm256_fmadd_pd( \
360  _mm256_castsi256_pd(ymm0), d, _mm256_castsi256_pd(zmm0))); \
361  ymm1 = _mm256_castpd_si256(_mm256_fmadd_pd( \
362  _mm256_castsi256_pd(ymm1), d, _mm256_castsi256_pd(zmm1))); \
363  ymm2 = _mm256_castpd_si256(_mm256_fmadd_pd( \
364  _mm256_castsi256_pd(ymm2), d, _mm256_castsi256_pd(zmm2))); \
365  ymm3 = _mm256_castpd_si256(_mm256_fmadd_pd( \
366  _mm256_castsi256_pd(ymm3), d, _mm256_castsi256_pd(zmm3))); \
367  ymm4 = _mm256_castpd_si256(_mm256_fmadd_pd( \
368  _mm256_castsi256_pd(ymm4), d, _mm256_castsi256_pd(zmm4))); \
369  ymm5 = _mm256_castpd_si256(_mm256_fmadd_pd( \
370  _mm256_castsi256_pd(ymm5), d, _mm256_castsi256_pd(zmm5))); \
371  ymm6 = _mm256_castpd_si256(_mm256_fmadd_pd( \
372  _mm256_castsi256_pd(ymm6), d, _mm256_castsi256_pd(zmm6))); \
373  ymm7 = _mm256_castpd_si256(_mm256_fmadd_pd( \
374  _mm256_castsi256_pd(ymm7), d, _mm256_castsi256_pd(zmm7)));
375 
376 #else // MCKL_USE_FMA
377 
378 #define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU64_PD \
379  const __m256d c = _mm256_set1_pd(Pow2<double, 52>::value); \
380  const __m256d d = _mm256_set1_pd(Pow2<double, 32>::value); \
381  const __m256i l = \
382  _mm256_set1_epi64x(static_cast<MCKL_INT64>(0xFFFFFFFF)); \
383  __m256i zmm0 = _mm256_and_si256(ymm0, l); \
384  __m256i zmm1 = _mm256_and_si256(ymm1, l); \
385  __m256i zmm2 = _mm256_and_si256(ymm2, l); \
386  __m256i zmm3 = _mm256_and_si256(ymm3, l); \
387  __m256i zmm4 = _mm256_and_si256(ymm4, l); \
388  __m256i zmm5 = _mm256_and_si256(ymm5, l); \
389  __m256i zmm6 = _mm256_and_si256(ymm6, l); \
390  __m256i zmm7 = _mm256_and_si256(ymm7, l); \
391  MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI64(32); \
392  ymm0 = _mm256_add_epi64(ymm0, _mm256_castpd_si256(c)); \
393  ymm1 = _mm256_add_epi64(ymm1, _mm256_castpd_si256(c)); \
394  ymm2 = _mm256_add_epi64(ymm2, _mm256_castpd_si256(c)); \
395  ymm3 = _mm256_add_epi64(ymm3, _mm256_castpd_si256(c)); \
396  ymm4 = _mm256_add_epi64(ymm4, _mm256_castpd_si256(c)); \
397  ymm5 = _mm256_add_epi64(ymm5, _mm256_castpd_si256(c)); \
398  ymm6 = _mm256_add_epi64(ymm6, _mm256_castpd_si256(c)); \
399  ymm7 = _mm256_add_epi64(ymm7, _mm256_castpd_si256(c)); \
400  zmm0 = _mm256_add_epi64(zmm0, _mm256_castpd_si256(c)); \
401  zmm1 = _mm256_add_epi64(zmm1, _mm256_castpd_si256(c)); \
402  zmm2 = _mm256_add_epi64(zmm2, _mm256_castpd_si256(c)); \
403  zmm3 = _mm256_add_epi64(zmm3, _mm256_castpd_si256(c)); \
404  zmm4 = _mm256_add_epi64(zmm4, _mm256_castpd_si256(c)); \
405  zmm5 = _mm256_add_epi64(zmm5, _mm256_castpd_si256(c)); \
406  zmm6 = _mm256_add_epi64(zmm6, _mm256_castpd_si256(c)); \
407  zmm7 = _mm256_add_epi64(zmm7, _mm256_castpd_si256(c)); \
408  ymm0 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm0), c)); \
409  ymm1 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm1), c)); \
410  ymm2 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm2), c)); \
411  ymm3 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm3), c)); \
412  ymm4 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm4), c)); \
413  ymm5 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm5), c)); \
414  ymm6 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm6), c)); \
415  ymm7 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm7), c)); \
416  zmm0 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm0), c)); \
417  zmm1 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm1), c)); \
418  zmm2 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm2), c)); \
419  zmm3 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm3), c)); \
420  zmm4 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm4), c)); \
421  zmm5 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm5), c)); \
422  zmm6 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm6), c)); \
423  zmm7 = _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm7), c)); \
424  ymm0 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm0), d)); \
425  ymm1 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm1), d)); \
426  ymm2 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm2), d)); \
427  ymm3 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm3), d)); \
428  ymm4 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm4), d)); \
429  ymm5 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm5), d)); \
430  ymm6 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm6), d)); \
431  ymm7 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm7), d)); \
432  ymm0 = _mm256_castpd_si256( \
433  _mm256_add_pd(_mm256_castsi256_pd(ymm0), _mm256_castsi256_pd(zmm0))); \
434  ymm1 = _mm256_castpd_si256( \
435  _mm256_add_pd(_mm256_castsi256_pd(ymm1), _mm256_castsi256_pd(zmm1))); \
436  ymm2 = _mm256_castpd_si256( \
437  _mm256_add_pd(_mm256_castsi256_pd(ymm2), _mm256_castsi256_pd(zmm2))); \
438  ymm3 = _mm256_castpd_si256( \
439  _mm256_add_pd(_mm256_castsi256_pd(ymm3), _mm256_castsi256_pd(zmm3))); \
440  ymm4 = _mm256_castpd_si256( \
441  _mm256_add_pd(_mm256_castsi256_pd(ymm4), _mm256_castsi256_pd(zmm4))); \
442  ymm5 = _mm256_castpd_si256( \
443  _mm256_add_pd(_mm256_castsi256_pd(ymm5), _mm256_castsi256_pd(zmm5))); \
444  ymm6 = _mm256_castpd_si256( \
445  _mm256_add_pd(_mm256_castsi256_pd(ymm6), _mm256_castsi256_pd(zmm6))); \
446  ymm7 = _mm256_castpd_si256( \
447  _mm256_add_pd(_mm256_castsi256_pd(ymm7), _mm256_castsi256_pd(zmm7)));
448 
449 #endif // MCKL_USE_FMA
450 
451 #define MCKL_RANDOM_INTERNAL_U01_AVX2_ADD_PS(a) \
452  ymm0 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm0), a)); \
453  ymm1 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm1), a)); \
454  ymm2 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm2), a)); \
455  ymm3 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm3), a)); \
456  ymm4 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm4), a)); \
457  ymm5 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm5), a)); \
458  ymm6 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm6), a)); \
459  ymm7 = _mm256_castps_si256(_mm256_add_ps(_mm256_castsi256_ps(ymm7), a));
460 
461 #define MCKL_RANDOM_INTERNAL_U01_AVX2_ADD_PD(a) \
462  ymm0 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm0), a)); \
463  ymm1 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm1), a)); \
464  ymm2 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm2), a)); \
465  ymm3 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm3), a)); \
466  ymm4 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm4), a)); \
467  ymm5 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm5), a)); \
468  ymm6 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm6), a)); \
469  ymm7 = _mm256_castpd_si256(_mm256_add_pd(_mm256_castsi256_pd(ymm7), a));
470 
471 #define MCKL_RANDOM_INTERNAL_U01_AVX2_MUL_PS(a) \
472  ymm0 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm0), a)); \
473  ymm1 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm1), a)); \
474  ymm2 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm2), a)); \
475  ymm3 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm3), a)); \
476  ymm4 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm4), a)); \
477  ymm5 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm5), a)); \
478  ymm6 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm6), a)); \
479  ymm7 = _mm256_castps_si256(_mm256_mul_ps(_mm256_castsi256_ps(ymm7), a));
480 
481 #define MCKL_RANDOM_INTERNAL_U01_AVX2_MUL_PD(a) \
482  ymm0 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm0), a)); \
483  ymm1 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm1), a)); \
484  ymm2 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm2), a)); \
485  ymm3 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm3), a)); \
486  ymm4 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm4), a)); \
487  ymm5 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm5), a)); \
488  ymm6 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm6), a)); \
489  ymm7 = _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(ymm7), a));
490 
491 #if MCKL_USE_FMA
492 
493 #define MCKL_RANDOM_INTERNAL_U01_AVX2_FMADD_PS(a, b) \
494  ymm0 = _mm256_castps_si256( \
495  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm0), a, b)); \
496  ymm1 = _mm256_castps_si256( \
497  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm1), a, b)); \
498  ymm2 = _mm256_castps_si256( \
499  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm2), a, b)); \
500  ymm3 = _mm256_castps_si256( \
501  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm3), a, b)); \
502  ymm4 = _mm256_castps_si256( \
503  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm4), a, b)); \
504  ymm5 = _mm256_castps_si256( \
505  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm5), a, b)); \
506  ymm6 = _mm256_castps_si256( \
507  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm6), a, b)); \
508  ymm7 = _mm256_castps_si256( \
509  _mm256_fmadd_ps(_mm256_castsi256_ps(ymm7), a, b));
510 
511 #define MCKL_RANDOM_INTERNAL_U01_AVX2_FMADD_PD(a, b) \
512  ymm0 = _mm256_castpd_si256( \
513  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm0), a, b)); \
514  ymm1 = _mm256_castpd_si256( \
515  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm1), a, b)); \
516  ymm2 = _mm256_castpd_si256( \
517  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm2), a, b)); \
518  ymm3 = _mm256_castpd_si256( \
519  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm3), a, b)); \
520  ymm4 = _mm256_castpd_si256( \
521  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm4), a, b)); \
522  ymm5 = _mm256_castpd_si256( \
523  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm5), a, b)); \
524  ymm6 = _mm256_castpd_si256( \
525  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm6), a, b)); \
526  ymm7 = _mm256_castpd_si256( \
527  _mm256_fmadd_pd(_mm256_castsi256_pd(ymm7), a, b));
528 
529 #else // MCKL_USE_FMA
530 
531 #define MCKL_RANDOM_INTERNAL_U01_AVX2_FMADD_PS(a, b) \
532  MCKL_RANDOM_INTERNAL_U01_AVX2_MUL_PS(a) \
533  MCKL_RANDOM_INTERNAL_U01_AVX2_ADD_PS(b)
534 
535 #define MCKL_RANDOM_INTERNAL_U01_AVX2_FMADD_PD(a, b) \
536  MCKL_RANDOM_INTERNAL_U01_AVX2_MUL_PD(a) \
537  MCKL_RANDOM_INTERNAL_U01_AVX2_ADD_PD(b)
538 
539 #endif // MCKL_USE_FMA
540 
541 namespace mckl {
542 
543 namespace internal {
544 
545 template <typename UIntType, typename RealType, typename Lower, typename Upper,
546  int = std::numeric_limits<UIntType>::digits>
547 class U01AVX2Impl : public U01GenericImpl<UIntType, RealType, Lower, Upper>
548 {
549 }; // class U01AVX2Impl
550 
551 template <typename UIntType, typename RealType, typename Lower, typename Upper>
553 {
554  public:
555  MCKL_INLINE static RealType eval(UIntType u)
556  {
558  }
559 
560  MCKL_INLINE static void eval(std::size_t n, const UIntType *u, RealType *r)
561  {
562  constexpr std::size_t S = 8;
563  constexpr std::size_t N = sizeof(__m256i) * S / sizeof(RealType);
564 
565  while (n >= N) {
567  n -= N;
568  u += N;
569  r += N;
570  }
571 
572  for (std::size_t i = 0; i != n; ++i) {
573  r[i] = eval(u[i]);
574  }
575  }
576 }; // class U01AVX2ImplBase
577 
578 template <typename UIntType, typename RealType, int Q,
579  int = std::numeric_limits<UIntType>::digits>
581  : public U01CanonicalGenericImpl<UIntType, RealType, Q>
582 {
583 }; // class U01CanonicalAVX2Impl
584 
585 template <typename UIntType, typename RealType, int Q>
587 {
588  public:
589  MCKL_INLINE static RealType eval(const UIntType *u)
590  {
592  }
593 
594  MCKL_INLINE static void eval(std::size_t n, const UIntType *u, RealType *r)
595  {
596  constexpr std::size_t S = 8;
597  constexpr std::size_t N = sizeof(__m256i) * S / sizeof(RealType);
598 
599  while (n >= N) {
601  n -= N;
602  u += N * Q;
603  r += N;
604  }
605 
606  for (std::size_t i = 0; i != n; ++i, u += Q) {
607  r[i] = eval(u);
608  }
609  }
610 }; // class U01CanonicalCanonicalAVX2ImplBase
611 
612 template <typename UIntType>
613 class U01AVX2Impl<UIntType, float, Closed, Closed, 32>
614  : public U01AVX2ImplBase<UIntType, float, Closed, Closed>
615 {
616  public:
618 
619  private:
621 
622  MCKL_INLINE static void eval(const UIntType *u, float *r)
623  {
624  const __m256 d25 = _mm256_set1_ps(Pow2<float, -25>::value);
625 
633  }
634 }; // class U01AVX2Impl
635 
636 template <typename UIntType>
637 class U01AVX2Impl<UIntType, float, Closed, Open, 32>
638  : public U01AVX2ImplBase<UIntType, float, Closed, Open>
639 {
640  public:
642 
643  private:
645 
646  MCKL_INLINE static void eval(const UIntType *u, float *r)
647  {
648  const __m256 d24 = _mm256_set1_ps(Pow2<float, -24>::value);
649 
655  }
656 }; // class U01AVX2Impl
657 
658 template <typename UIntType>
659 class U01AVX2Impl<UIntType, float, Open, Closed, 32>
660  : public U01AVX2ImplBase<UIntType, float, Open, Closed>
661 {
662  public:
664 
665  private:
667 
668  MCKL_INLINE static void eval(const UIntType *u, float *r)
669  {
670  const __m256 d24 = _mm256_set1_ps(Pow2<float, -24>::value);
671 
677  }
678 }; // class U01AVX2Impl
679 
680 template <typename UIntType>
681 class U01AVX2Impl<UIntType, float, Open, Open, 32>
682  : public U01AVX2ImplBase<UIntType, float, Open, Open>
683 {
684  public:
686 
687  private:
689 
690  MCKL_INLINE static void eval(const UIntType *u, float *r)
691  {
692  const __m256 d23 = _mm256_set1_ps(Pow2<float, -23>::value);
693  const __m256 d24 = _mm256_set1_ps(Pow2<float, -24>::value);
694 
700  }
701 }; // class U01AVX2Impl
702 
703 template <typename UIntType>
704 class U01AVX2Impl<UIntType, double, Closed, Closed, 32>
705  : public U01AVX2ImplBase<UIntType, double, Closed, Closed>
706 {
707  public:
709 
710  private:
712 
713  MCKL_INLINE static void eval(const UIntType *u, double *r)
714  {
715  const __m256d d32 = _mm256_set1_pd(Pow2<double, -32>::value);
716 
722  }
723 }; // class U01AVX2Impl
724 
725 template <typename UIntType>
726 class U01AVX2Impl<UIntType, double, Closed, Open, 32>
727  : public U01AVX2ImplBase<UIntType, double, Closed, Open>
728 {
729  public:
731 
732  private:
734 
735  MCKL_INLINE static void eval(const UIntType *u, double *r)
736  {
737  const __m256d d32 = _mm256_set1_pd(Pow2<double, -32>::value);
738 
743  }
744 }; // class U01AVX2Impl
745 
746 template <typename UIntType>
747 class U01AVX2Impl<UIntType, double, Open, Closed, 32>
748  : public U01AVX2ImplBase<UIntType, double, Open, Closed>
749 {
750  public:
752 
753  private:
755 
756  MCKL_INLINE static void eval(const UIntType *u, double *r)
757  {
758  const __m256d d32 = _mm256_set1_pd(Pow2<double, -32>::value);
759 
764  }
765 }; // class U01AVX2Impl
766 
767 template <typename UIntType>
768 class U01AVX2Impl<UIntType, double, Open, Open, 32>
769  : public U01AVX2ImplBase<UIntType, double, Open, Open>
770 {
771  public:
773 
774  private:
776 
777  MCKL_INLINE static void eval(const UIntType *u, double *r)
778  {
779  const __m256d d32 = _mm256_set1_pd(Pow2<double, -32>::value);
780  const __m256d d33 = _mm256_set1_pd(Pow2<double, -33>::value);
781 
786  }
787 }; // class U01AVX2Impl
788 
789 template <typename UIntType>
790 class U01AVX2Impl<UIntType, double, Closed, Closed, 64>
791  : public U01AVX2ImplBase<UIntType, double, Closed, Closed>
792 {
793  public:
795 
796  private:
798 
799  MCKL_INLINE static void eval(const UIntType *u, double *r)
800  {
801  const __m256d d54 = _mm256_set1_pd(Pow2<double, -54>::value);
802 
810  }
811 }; // class U01AVX2Impl
812 
813 template <typename UIntType>
814 class U01AVX2Impl<UIntType, double, Closed, Open, 64>
815  : public U01AVX2ImplBase<UIntType, double, Closed, Open>
816 {
817  public:
819 
820  private:
822 
823  MCKL_INLINE static void eval(const UIntType *u, double *r)
824  {
825  const __m256d d53 = _mm256_set1_pd(Pow2<double, -53>::value);
826 
832  }
833 }; // class U01AVX2Impl
834 
835 template <typename UIntType>
836 class U01AVX2Impl<UIntType, double, Open, Closed, 64>
837  : public U01AVX2ImplBase<UIntType, double, Open, Closed>
838 {
839  public:
841 
842  private:
844 
845  MCKL_INLINE static void eval(const UIntType *u, double *r)
846  {
847  const __m256d d53 = _mm256_set1_pd(Pow2<double, -53>::value);
848 
854  }
855 }; // class U01AVX2Impl
856 
857 template <typename UIntType>
858 class U01AVX2Impl<UIntType, double, Open, Open, 64>
859  : public U01AVX2ImplBase<UIntType, double, Open, Open>
860 {
861  public:
863 
864  private:
866 
867  MCKL_INLINE static void eval(const UIntType *u, double *r)
868  {
869  const __m256d d52 = _mm256_set1_pd(Pow2<double, -52>::value);
870  const __m256d d53 = _mm256_set1_pd(Pow2<double, -53>::value);
871 
877  }
878 }; // class U01AVX2Impl
879 
880 template <typename UIntType>
881 class U01CanonicalAVX2Impl<UIntType, float, 1, 32>
882  : public U01CanonicalAVX2ImplBase<UIntType, float, 1>
883 {
884  public:
886 
887  private:
889 
890  MCKL_INLINE static void eval(const UIntType *u, float *r)
891  {
892  const __m256 d32 = _mm256_set1_ps(Pow2<float, -32>::value);
893 
898  }
899 }; // class U01CanonicalAVX2Impl
900 
901 template <typename UIntType>
902 class U01CanonicalAVX2Impl<UIntType, double, 2, 32>
903  : public U01CanonicalAVX2ImplBase<UIntType, double, 2>
904 {
905  public:
907 
908  private:
910 
911  MCKL_INLINE static void eval(const UIntType *u, double *r)
912  {
913  const __m256d d32 = _mm256_set1_pd(Pow2<double, -32>::value);
914  const __m256d d64 = _mm256_set1_pd(Pow2<double, -64>::value);
915  const __m256d c = _mm256_set1_pd(Pow2<double, 52>::value);
916  const __m256i l =
917  _mm256_set1_epi64x(static_cast<MCKL_INT64>(0xFFFFFFFF));
918 
920 
921  __m256i zmm0 = _mm256_and_si256(ymm0, l);
922  __m256i zmm1 = _mm256_and_si256(ymm1, l);
923  __m256i zmm2 = _mm256_and_si256(ymm2, l);
924  __m256i zmm3 = _mm256_and_si256(ymm3, l);
925  __m256i zmm4 = _mm256_and_si256(ymm4, l);
926  __m256i zmm5 = _mm256_and_si256(ymm5, l);
927  __m256i zmm6 = _mm256_and_si256(ymm6, l);
928  __m256i zmm7 = _mm256_and_si256(ymm7, l);
929 
931 
932  ymm0 = _mm256_add_epi64(ymm0, _mm256_castpd_si256(c));
933  ymm1 = _mm256_add_epi64(ymm1, _mm256_castpd_si256(c));
934  ymm2 = _mm256_add_epi64(ymm2, _mm256_castpd_si256(c));
935  ymm3 = _mm256_add_epi64(ymm3, _mm256_castpd_si256(c));
936  ymm4 = _mm256_add_epi64(ymm4, _mm256_castpd_si256(c));
937  ymm5 = _mm256_add_epi64(ymm5, _mm256_castpd_si256(c));
938  ymm6 = _mm256_add_epi64(ymm6, _mm256_castpd_si256(c));
939  ymm7 = _mm256_add_epi64(ymm7, _mm256_castpd_si256(c));
940 
941  zmm0 = _mm256_add_epi64(zmm0, _mm256_castpd_si256(c));
942  zmm1 = _mm256_add_epi64(zmm1, _mm256_castpd_si256(c));
943  zmm2 = _mm256_add_epi64(zmm2, _mm256_castpd_si256(c));
944  zmm3 = _mm256_add_epi64(zmm3, _mm256_castpd_si256(c));
945  zmm4 = _mm256_add_epi64(zmm4, _mm256_castpd_si256(c));
946  zmm5 = _mm256_add_epi64(zmm5, _mm256_castpd_si256(c));
947  zmm6 = _mm256_add_epi64(zmm6, _mm256_castpd_si256(c));
948  zmm7 = _mm256_add_epi64(zmm7, _mm256_castpd_si256(c));
949 
950  ymm0 =
951  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm0), c));
952  ymm1 =
953  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm1), c));
954  ymm2 =
955  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm2), c));
956  ymm3 =
957  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm3), c));
958  ymm4 =
959  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm4), c));
960  ymm5 =
961  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm5), c));
962  ymm6 =
963  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm6), c));
964  ymm7 =
965  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(ymm7), c));
966 
967  zmm0 =
968  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm0), c));
969  zmm1 =
970  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm1), c));
971  zmm2 =
972  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm2), c));
973  zmm3 =
974  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm3), c));
975  zmm4 =
976  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm4), c));
977  zmm5 =
978  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm5), c));
979  zmm6 =
980  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm6), c));
981  zmm7 =
982  _mm256_castpd_si256(_mm256_sub_pd(_mm256_castsi256_pd(zmm7), c));
983 
985 
986 #if MCKL_USE_FMA
987 
988  ymm0 = _mm256_castpd_si256(_mm256_fmadd_pd(
989  _mm256_castsi256_pd(zmm0), d64, _mm256_castsi256_pd(ymm0)));
990  ymm1 = _mm256_castpd_si256(_mm256_fmadd_pd(
991  _mm256_castsi256_pd(zmm1), d64, _mm256_castsi256_pd(ymm1)));
992  ymm2 = _mm256_castpd_si256(_mm256_fmadd_pd(
993  _mm256_castsi256_pd(zmm2), d64, _mm256_castsi256_pd(ymm2)));
994  ymm3 = _mm256_castpd_si256(_mm256_fmadd_pd(
995  _mm256_castsi256_pd(zmm3), d64, _mm256_castsi256_pd(ymm3)));
996  ymm4 = _mm256_castpd_si256(_mm256_fmadd_pd(
997  _mm256_castsi256_pd(zmm4), d64, _mm256_castsi256_pd(ymm4)));
998  ymm5 = _mm256_castpd_si256(_mm256_fmadd_pd(
999  _mm256_castsi256_pd(zmm5), d64, _mm256_castsi256_pd(ymm5)));
1000  ymm6 = _mm256_castpd_si256(_mm256_fmadd_pd(
1001  _mm256_castsi256_pd(zmm6), d64, _mm256_castsi256_pd(ymm6)));
1002  ymm7 = _mm256_castpd_si256(_mm256_fmadd_pd(
1003  _mm256_castsi256_pd(zmm7), d64, _mm256_castsi256_pd(ymm7)));
1004 
1005 #else // MCKL_USE_FMA
1006 
1007  zmm0 =
1008  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm0), d64));
1009  zmm1 =
1010  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm1), d64));
1011  zmm2 =
1012  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm2), d64));
1013  zmm3 =
1014  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm3), d64));
1015  zmm4 =
1016  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm4), d64));
1017  zmm5 =
1018  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm5), d64));
1019  zmm6 =
1020  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm6), d64));
1021  zmm7 =
1022  _mm256_castpd_si256(_mm256_mul_pd(_mm256_castsi256_pd(zmm7), d64));
1023 
1024  ymm0 = _mm256_castpd_si256(_mm256_add_pd(
1025  _mm256_castsi256_pd(ymm0), _mm256_castsi256_pd(zmm0)));
1026  ymm1 = _mm256_castpd_si256(_mm256_add_pd(
1027  _mm256_castsi256_pd(ymm1), _mm256_castsi256_pd(zmm1)));
1028  ymm2 = _mm256_castpd_si256(_mm256_add_pd(
1029  _mm256_castsi256_pd(ymm2), _mm256_castsi256_pd(zmm2)));
1030  ymm3 = _mm256_castpd_si256(_mm256_add_pd(
1031  _mm256_castsi256_pd(ymm3), _mm256_castsi256_pd(zmm3)));
1032  ymm4 = _mm256_castpd_si256(_mm256_add_pd(
1033  _mm256_castsi256_pd(ymm4), _mm256_castsi256_pd(zmm4)));
1034  ymm5 = _mm256_castpd_si256(_mm256_add_pd(
1035  _mm256_castsi256_pd(ymm5), _mm256_castsi256_pd(zmm5)));
1036  ymm6 = _mm256_castpd_si256(_mm256_add_pd(
1037  _mm256_castsi256_pd(ymm6), _mm256_castsi256_pd(zmm6)));
1038  ymm7 = _mm256_castpd_si256(_mm256_add_pd(
1039  _mm256_castsi256_pd(ymm7), _mm256_castsi256_pd(zmm7)));
1040 
1041 #endif // MCKL_USE_FMA
1042 
1044  }
1045 }; // class U01CanonicalAVX2Impl
1046 
1047 template <typename UIntType>
1048 class U01CanonicalAVX2Impl<UIntType, double, 1, 64>
1049  : public U01CanonicalAVX2ImplBase<UIntType, double, 1>
1050 {
1051  public:
1053 
1054  private:
1056 
1057  MCKL_INLINE static void eval(const UIntType *u, double *r)
1058  {
1059  const __m256d d64 = _mm256_set1_pd(Pow2<double, -64>::value);
1060 
1065  }
1066 }; // class U01CanonicalAVX2Impl
1067 
1068 } // namespace internal
1069 
1070 } // namespace mckl
1071 
1073 
1074 #endif // MCKL_RANDOM_INTERNAL_U01_AVX2_HPP
#define MCKL_RANDOM_INTERNAL_U01_AVX2_MUL_PD(a)
Definition: u01_avx2.hpp:481
#define MCKL_PUSH_GCC_WARNING(warning)
Definition: compiler.h:78
#define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU64_PD_52
Definition: u01_avx2.hpp:292
#define MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI32(imm8)
Definition: u01_avx2.hpp:114
#define MCKL_RANDOM_INTERNAL_U01_AVX2_SLLI_EPI32(imm8)
Definition: u01_avx2.hpp:104
#define MCKL_RANDOM_INTERNAL_U01_AVX2_AND1ADD_EPI64
Definition: u01_avx2.hpp:93
static RealType eval(const UIntType *u)
#define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU64_PD
Definition: u01_avx2.hpp:313
#define MCKL_RANDOM_INTERNAL_U01_AVX2_STOREU_PS(r)
Definition: u01_avx2.hpp:62
#define MCKL_RANDOM_INTERNAL_U01_AVX2_STOREU_PD(r)
Definition: u01_avx2.hpp:72
#define MCKL_RANDOM_INTERNAL_U01_AVX2_MUL_PS(a)
Definition: u01_avx2.hpp:471
#define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU32_PS
Definition: u01_avx2.hpp:156
#define MCKL_RANDOM_INTERNAL_U01_AVX2_CVTEPU32_PS_31
Definition: u01_avx2.hpp:144
#define MCKL_RANDOM_INTERNAL_U01_AVX2_FMADD_PS(a, b)
Definition: u01_avx2.hpp:493
Definition: mcmc.hpp:40
#define MCKL_RANDOM_INTERNAL_U01_AVX2_FMADD_PD(a, b)
Definition: u01_avx2.hpp:511
#define MCKL_RANDOM_INTERNAL_U01_AVX2_LOADU_SI256(u)
Definition: u01_avx2.hpp:40
#define MCKL_RANDOM_INTERNAL_U01_AVX2_SLLI_EPI64(imm8)
Definition: u01_avx2.hpp:124
#define MCKL_RANDOM_INTERNAL_U01_AVX2_AND1ADD_EPI32
Definition: u01_avx2.hpp:82
Pow2Impl< RealType, P > Pow2
Definition: const_math.hpp:171
#define MCKL_RANDOM_INTERNAL_U01_AVX2_SRLI_EPI64(imm8)
Definition: u01_avx2.hpp:134
#define MCKL_INLINE
Definition: clang.h:147
#define MCKL_RANDOM_INTERNAL_U01_AVX2_LOADU_SI256_CVTEPU32_EPI64(u)
Definition: u01_avx2.hpp:51
#define MCKL_POP_GCC_WARNING
Definition: compiler.h:79