Line data Source code
1 : ///////////////////////////////////////////////////////////////////////////
2 : // Inastemp - Berenger Bramas MPCDF - 2016
3 : // Under MIT Licence, please you must read the LICENCE file.
4 : ///////////////////////////////////////////////////////////////////////////
5 : #ifndef INAVECAVXDOUBLE_HPP
6 : #define INAVECAVXDOUBLE_HPP
7 :
8 : #include "InastempGlobal.h"
9 : #include "Common/InaIfElse.hpp"
10 : #include "Common/InaUtils.hpp"
11 :
12 : #ifndef INASTEMP_USE_AVX
13 : #error InaVecAVX<double> is included but AVX is not enable in the configuration
14 : #endif
15 :
16 : #include "Common/InaFastExp.hpp"
17 :
18 : #include <immintrin.h>
19 : #include <cmath>
20 : #include <initializer_list>
21 :
22 : // Forward declarations
23 : template <class RealType>
24 : class InaVecMaskAVX;
25 :
26 : template <class RealType>
27 : class InaVecAVX;
28 :
29 : // Mask type
30 : template <>
31 : class alignas(32) InaVecMaskAVX<double> {
32 : __m256i mask;
33 : public:
34 : // Classic constructors
35 : inline InaVecMaskAVX(){}
36 :
37 : inline InaVecMaskAVX(const InaVecMaskAVX&) = default;
38 : inline InaVecMaskAVX& operator=(const InaVecMaskAVX&) = default;
39 :
40 : // Native data type compatibility
41 : inline /*not explicit*/ InaVecMaskAVX(const __m256i inMask)
42 : : mask(inMask){}
43 :
44 : inline InaVecMaskAVX& operator=(const __m256i inMask){
45 : mask = inMask;
46 : return (*this);
47 : }
48 :
49 : inline explicit operator __m256i() const{
50 : return mask;
51 : }
52 :
53 : inline __m256i getMask() const{
54 : return mask;
55 : }
56 :
57 : // Bool data type compatibility
58 40 : inline explicit InaVecMaskAVX(const bool inBool){
59 40 : mask = (inBool? _mm256_set1_epi64x(static_cast<long long>(0xFFFFFFFFFFFFFFFFL)) : _mm256_setzero_si256());
60 : }
61 :
62 : inline InaVecMaskAVX& operator=(const bool inBool){
63 : mask = (inBool? _mm256_set1_epi64x(static_cast<long long>(0xFFFFFFFFFFFFFFFFL)) : _mm256_setzero_si256());
64 : return (*this);
65 : }
66 :
67 : // Binary methods
68 : inline InaVecMaskAVX Not() const{
69 : return NotAnd(mask, _mm256_set1_epi64x(static_cast<long long>(0xFFFFFFFFFFFFFFFFL)));
70 : }
71 :
72 : inline bool isAllTrue() const{
73 : // true if all FF => !FF => 0 & FF => 0
74 20 : return _mm256_testc_si256(mask, _mm256_set1_epi64x(static_cast<long long>(0xFFFFFFFFFFFFFFFFL)));
75 : }
76 :
77 : inline bool isAllFalse() const{
78 : // true if all zero
79 20 : return _mm256_testz_si256(mask, mask);
80 : }
81 :
82 : // Double args methods
83 : inline static InaVecMaskAVX And(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
84 : // AVX2 return InaVecMaskAVX(_mm256_and_si256(inMask1.mask, inMask2.mask));
85 : return InaVecMaskAVX(_mm256_castpd_si256(_mm256_and_pd(_mm256_castsi256_pd(inMask1.mask),
86 : _mm256_castsi256_pd(inMask2.mask))));
87 : }
88 :
89 : inline static InaVecMaskAVX NotAnd(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
90 : // AVX2 return InaVecMaskAVX(_mm256_andnot_si256(inMask1.mask, inMask2.mask));
91 : return InaVecMaskAVX(_mm256_castpd_si256(_mm256_andnot_pd(_mm256_castsi256_pd(inMask1.mask),
92 : _mm256_castsi256_pd(inMask2.mask))));
93 : }
94 :
95 : inline static InaVecMaskAVX Or(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
96 : // AVX2 return InaVecMaskAVX(_mm256_or_si256(inMask1.mask, inMask2.mask));
97 144 : return InaVecMaskAVX(_mm256_castpd_si256(_mm256_or_pd(_mm256_castsi256_pd(inMask1.mask),
98 48 : _mm256_castsi256_pd(inMask2.mask))));
99 : }
100 :
101 : inline static InaVecMaskAVX Xor(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
102 : // AVX2 return InaVecMaskAVX(_mm256_xor_si256(inMask1.mask, inMask2.mask));
103 : return InaVecMaskAVX(_mm256_castpd_si256(_mm256_xor_pd(_mm256_castsi256_pd(inMask1.mask),
104 : _mm256_castsi256_pd(inMask2.mask))));
105 : }
106 :
107 : inline static bool IsEqual(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
108 40 : return _mm256_testz_si256(_mm256_castpd_si256(_mm256_xor_pd(_mm256_castsi256_pd(inMask1.mask),
109 8 : _mm256_castsi256_pd(inMask2.mask))),
110 8 : _mm256_set1_epi64x(static_cast<long long>(0xFFFFFFFFFFFFFFFFL))); // return CF
111 : }
112 :
113 : inline static bool IsNotEqual(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
114 20 : return !_mm256_testz_si256(_mm256_castpd_si256(_mm256_xor_pd(_mm256_castsi256_pd(inMask1.mask),
115 4 : _mm256_castsi256_pd(inMask2.mask))),
116 4 : _mm256_set1_epi64x(static_cast<long long>(0xFFFFFFFFFFFFFFFFL))); // return CF
117 : }
118 : };
119 :
120 : // Mask must have operators
121 : inline InaVecMaskAVX<double> operator&(const InaVecMaskAVX<double>& inMask1, const InaVecMaskAVX<double>& inMask2){
122 : return InaVecMaskAVX<double>::And(inMask1, inMask2);
123 : }
124 :
125 : inline InaVecMaskAVX<double> operator|(const InaVecMaskAVX<double>& inMask1, const InaVecMaskAVX<double>& inMask2){
126 : return InaVecMaskAVX<double>::Or(inMask1, inMask2);
127 : }
128 :
129 : inline InaVecMaskAVX<double> operator^(const InaVecMaskAVX<double>& inMask1, const InaVecMaskAVX<double>& inMask2){
130 : return InaVecMaskAVX<double>::Xor(inMask1, inMask2);
131 : }
132 :
133 : inline bool operator==(const InaVecMaskAVX<double>& inMask1, const InaVecMaskAVX<double>& inMask2){
134 8 : return InaVecMaskAVX<double>::IsEqual(inMask1, inMask2);
135 : }
136 :
137 : inline bool operator!=(const InaVecMaskAVX<double>& inMask1, const InaVecMaskAVX<double>& inMask2){
138 4 : return InaVecMaskAVX<double>::IsNotEqual(inMask1, inMask2);
139 : }
140 :
141 : // Vec type
142 : template <>
143 : class alignas(32) InaVecAVX<double> {
144 : protected:
145 : __m256d vec;
146 :
147 : public:
148 : using VecRawType = __m256d;
149 : using MaskType = InaVecMaskAVX<double>;
150 : using RealType = double;
151 : [[deprecated("Please use the method instead")]]
152 : static const int VecLength = 4;
153 : static const int Alignement= 32;
154 : static const bool IsOfFixedSize = true;
155 :
156 : static constexpr int GetVecLength(){
157 : return 4;
158 : }
159 :
160 : static constexpr bool IsRealFma(){
161 : return false;
162 : }
163 :
164 102 : inline InaVecAVX(){}
165 : inline InaVecAVX(const InaVecAVX&) = default;
166 : inline InaVecAVX& operator = (const InaVecAVX&) = default;
167 :
168 : // Constructor from raw type
169 : inline /*not explicit*/ InaVecAVX(const __m256d inVec)
170 : : vec(inVec){
171 : }
172 :
173 : inline InaVecAVX& operator=(const __m256d inVec){
174 : vec = inVec;
175 : return *this;
176 : }
177 :
178 : inline void setFromRawType(const __m256d inVec){
179 : vec = inVec;
180 : }
181 :
182 : inline explicit operator __m256d() const{
183 : return vec;
184 : }
185 :
186 : inline __m256d getVec() const{
187 : return vec;
188 : }
189 :
190 : // Constructor from scalar
191 : inline /*not explicit*/ InaVecAVX(const double val)
192 4346 : : vec(_mm256_set1_pd(val)){
193 : }
194 :
195 : inline InaVecAVX& operator=(const double val){
196 : vec = _mm256_set1_pd(val);
197 : return *this;
198 : }
199 :
200 : inline void setFromScalar(const double val){
201 : vec = _mm256_set1_pd(val);
202 : }
203 :
204 : // Constructor from vec
205 : inline InaVecAVX(const std::initializer_list<double> lst)
206 24 : : InaVecAVX(lst.begin()){
207 : }
208 :
209 : inline explicit InaVecAVX(const double ptr[])
210 4436 : : vec(_mm256_loadu_pd(ptr)){
211 : }
212 :
213 : inline InaVecAVX& setFromArray(const double ptr[]){
214 340 : vec = _mm256_loadu_pd(ptr);
215 : return *this;
216 : }
217 :
218 : inline InaVecAVX& setFromAlignedArray(const double ptr[]){
219 50 : vec = _mm256_load_pd(ptr);
220 : return *this;
221 : }
222 :
223 : inline InaVecAVX& setFromIndirectArray(const double values[], const int inIndirection[]) {
224 150 : vec = _mm256_set_pd(
225 30 : values[inIndirection[3]],
226 30 : values[inIndirection[2]],
227 30 : values[inIndirection[1]],
228 30 : values[inIndirection[0]]);
229 : return *this;
230 : }
231 :
232 30 : inline InaVecAVX& setFromIndirect2DArray(const double inArray[], const int inIndirection1[],
233 : const int inLeadingDimension, const int inIndirection2[]){
234 150 : vec = _mm256_set_pd(
235 30 : inArray[inIndirection1[3] * inLeadingDimension + inIndirection2[3]],
236 30 : inArray[inIndirection1[2] * inLeadingDimension + inIndirection2[2]],
237 30 : inArray[inIndirection1[1] * inLeadingDimension + inIndirection2[1]],
238 30 : inArray[inIndirection1[0] * inLeadingDimension + inIndirection2[0]]);
239 30 : return *this;
240 : }
241 :
242 : // Move back to array
243 : inline void storeInArray(double ptr[]) const {
244 30492 : _mm256_storeu_pd(ptr, vec);
245 : }
246 :
247 : inline void storeInAlignedArray(double ptr[]) const {
248 5820 : _mm256_store_pd(ptr, vec);
249 : }
250 :
251 : // Acce to individual values
252 : inline double at(const int index) const {
253 : alignas(Alignement) double allval[GetVecLength()];
254 28720 : _mm256_store_pd(allval, vec);
255 14360 : return allval[index];
256 : }
257 :
258 : // Horizontal operation
259 : inline double horizontalSum() const {
260 3932 : const __m128d valupper = _mm256_extractf128_pd(vec, 1);
261 3932 : const __m128d rest = _mm256_castpd256_pd128(vec);
262 1990 : const __m128d valval = _mm_add_pd(valupper, rest);
263 3932 : const __m128d res = _mm_add_pd(_mm_permute_pd(valval, 1), valval);
264 1990 : return _mm_cvtsd_f64(res);
265 : }
266 :
267 : inline double horizontalMul() const {
268 60 : const __m128d valupper = _mm256_extractf128_pd(vec, 1);
269 60 : const __m128d rest = _mm256_castpd256_pd128(vec);
270 30 : const __m128d valval = _mm_mul_pd(valupper, rest);
271 60 : const __m128d res = _mm_mul_pd(_mm_permute_pd(valval, 1), valval);
272 30 : return _mm_cvtsd_f64(res);
273 : }
274 :
275 : inline double minInVec() const {
276 160 : const __m128d valupper = _mm256_extractf128_pd(vec, 1);
277 160 : const __m128d rest = _mm256_castpd256_pd128(vec);
278 80 : const __m128d valval = _mm_min_pd(valupper, rest);
279 160 : const __m128d res = _mm_min_pd(_mm_permute_pd(valval, 1), valval);
280 80 : return _mm_cvtsd_f64(res);
281 : }
282 :
283 : inline double maxInVec() const {
284 160 : const __m128d valupper = _mm256_extractf128_pd(vec, 1);
285 160 : const __m128d rest = _mm256_castpd256_pd128(vec);
286 80 : const __m128d valval = _mm_max_pd(valupper, rest);
287 160 : const __m128d res = _mm_max_pd(_mm_permute_pd(valval, 1), valval);
288 80 : return _mm_cvtsd_f64(res);
289 : }
290 :
291 : inline InaVecAVX sqrt() const {
292 40 : return _mm256_sqrt_pd(vec);
293 : }
294 :
295 30 : inline InaVecAVX exp() const {
296 : #ifdef __INTEL_COMPILER
297 : return _mm256_exp_pd(vec);
298 : #else
299 30 : const __m256d COEFF_LOG2E = _mm256_set1_pd(double(InaFastExp::CoeffLog2E()));
300 30 : const __m256d COEFF_A = _mm256_set1_pd(double(InaFastExp::CoeffA64()));
301 30 : const __m256d COEFF_B = _mm256_set1_pd(double(InaFastExp::CoeffB64()));
302 30 : const __m256d COEFF_P5_X = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_8()));
303 30 : const __m256d COEFF_P5_Y = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_7()));
304 30 : const __m256d COEFF_P5_Z = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_6()));
305 30 : const __m256d COEFF_P5_A = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_5()));
306 30 : const __m256d COEFF_P5_B = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_4()));
307 30 : const __m256d COEFF_P5_C = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_3()));
308 30 : const __m256d COEFF_P5_D = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_2()));
309 30 : const __m256d COEFF_P5_E = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_1()));
310 30 : const __m256d COEFF_P5_F = _mm256_set1_pd(double(InaFastExp::GetCoefficient9_0()));
311 :
312 60 : __m256d x = _mm256_mul_pd(vec, COEFF_LOG2E);
313 :
314 90 : const __m256d fractional_part = _mm256_sub_pd(x, InaVecAVX(x).floor().vec);
315 :
316 450 : __m256d factor = _mm256_add_pd(_mm256_mul_pd(_mm256_add_pd(
317 : _mm256_mul_pd(_mm256_add_pd( _mm256_mul_pd(_mm256_add_pd(
318 : _mm256_mul_pd(_mm256_add_pd( _mm256_mul_pd(_mm256_add_pd(
319 : _mm256_mul_pd(_mm256_add_pd( _mm256_mul_pd(_mm256_add_pd(_mm256_mul_pd(
320 : COEFF_P5_X, fractional_part), COEFF_P5_Y), fractional_part),
321 : COEFF_P5_Z),fractional_part), COEFF_P5_A), fractional_part),
322 : COEFF_P5_B), fractional_part), COEFF_P5_C),fractional_part),
323 : COEFF_P5_D), fractional_part), COEFF_P5_E),fractional_part),
324 30 : COEFF_P5_F);
325 :
326 30 : x = _mm256_sub_pd(x,factor);
327 :
328 60 : x = _mm256_add_pd(_mm256_mul_pd(COEFF_A, x), COEFF_B);
329 :
330 30 : __m128d valupper = _mm256_extractf128_pd(x, 1);
331 30 : __m128d vallower = _mm256_castpd256_pd128(x);
332 :
333 30 : alignas(64) long long int allvalint[GetVecLength()] = { _mm_cvtsd_si64(vallower),
334 60 : _mm_cvtsd_si64(_mm_shuffle_pd(vallower, vallower, 1)),
335 30 : _mm_cvtsd_si64(valupper),
336 150 : _mm_cvtsd_si64(_mm_shuffle_pd(valupper, valupper, 1)) };
337 :
338 60 : return _mm256_castsi256_pd(_mm256_load_si256(reinterpret_cast<const __m256i*>(allvalint)));
339 : #endif
340 : }
341 :
342 20 : inline InaVecAVX expLowAcc() const {
343 20 : const __m256d COEFF_LOG2E = _mm256_set1_pd(double(InaFastExp::CoeffLog2E()));
344 20 : const __m256d COEFF_A = _mm256_set1_pd(double(InaFastExp::CoeffA64()));
345 20 : const __m256d COEFF_B = _mm256_set1_pd(double(InaFastExp::CoeffB64()));
346 20 : const __m256d COEFF_P5_C = _mm256_set1_pd(double(InaFastExp::GetCoefficient4_3()));
347 20 : const __m256d COEFF_P5_D = _mm256_set1_pd(double(InaFastExp::GetCoefficient4_2()));
348 20 : const __m256d COEFF_P5_E = _mm256_set1_pd(double(InaFastExp::GetCoefficient4_1()));
349 20 : const __m256d COEFF_P5_F = _mm256_set1_pd(double(InaFastExp::GetCoefficient4_0()));
350 :
351 40 : __m256d x = _mm256_mul_pd(vec, COEFF_LOG2E);
352 :
353 60 : const __m256d fractional_part = _mm256_sub_pd(x, InaVecAVX(x).floor().vec);
354 :
355 100 : __m256d factor = _mm256_add_pd(_mm256_mul_pd(_mm256_add_pd(
356 : _mm256_mul_pd(_mm256_add_pd(_mm256_mul_pd(
357 : COEFF_P5_C, fractional_part),
358 : COEFF_P5_D), fractional_part),
359 : COEFF_P5_E), fractional_part),
360 20 : COEFF_P5_F);
361 :
362 20 : x = _mm256_sub_pd(x,factor);
363 :
364 40 : x = _mm256_add_pd(_mm256_mul_pd(COEFF_A, x), COEFF_B);
365 :
366 20 : __m128d valupper = _mm256_extractf128_pd(x, 1);
367 20 : __m128d vallower = _mm256_castpd256_pd128(x);
368 :
369 20 : alignas(64) long long int allvalint[GetVecLength()] = { _mm_cvtsd_si64(vallower),
370 40 : _mm_cvtsd_si64(_mm_shuffle_pd(vallower, vallower, 1)),
371 20 : _mm_cvtsd_si64(valupper),
372 100 : _mm_cvtsd_si64(_mm_shuffle_pd(valupper, valupper, 1)) };
373 :
374 40 : return _mm256_castsi256_pd(_mm256_load_si256(reinterpret_cast<const __m256i*>(allvalint)));
375 : }
376 :
377 : inline InaVecAVX rsqrt() const {
378 40 : return _mm256_set1_pd(1) / _mm256_sqrt_pd(vec);
379 : }
380 :
381 : inline InaVecAVX abs() const {
382 30 : const __m256d minus0 = _mm256_castsi256_pd(_mm256_set1_epi64x(static_cast<long long>(0x8000000000000000L)));
383 60 : return _mm256_andnot_pd(minus0, vec);
384 : }
385 :
386 : inline InaVecAVX floor() const {
387 200 : return _mm256_floor_pd(vec);
388 : }
389 :
390 : inline InaVecAVX signOf() const {
391 50 : const __m256d minus0 = _mm256_castsi256_pd(_mm256_set1_epi64x(static_cast<long long>(0x8000000000000000L)));
392 100 : const __m256d signs = _mm256_and_pd(vec, minus0);
393 : return _mm256_and_pd(_mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_NEQ_OQ),
394 200 : _mm256_or_pd(signs, _mm256_set1_pd(1)));
395 : }
396 :
397 : inline InaVecAVX isPositive() const {
398 100 : const __m256d greater = _mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_LE_OQ);
399 50 : const __m256d ones = _mm256_set1_pd(1);
400 50 : return _mm256_and_pd(greater, ones);
401 : }
402 :
403 : inline InaVecAVX isNegative() const {
404 100 : const __m256d less = _mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_GE_OQ);
405 50 : const __m256d ones = _mm256_set1_pd(1);
406 50 : return _mm256_and_pd(less, ones);
407 : }
408 :
409 : inline InaVecAVX isPositiveStrict() const {
410 100 : const __m256d greater = _mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_LT_OQ);
411 50 : const __m256d ones = _mm256_set1_pd(1);
412 50 : return _mm256_and_pd(greater, ones);
413 : }
414 :
415 : inline InaVecAVX isNegativeStrict() const {
416 100 : const __m256d less = _mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_GT_OQ);
417 50 : const __m256d ones = _mm256_set1_pd(1);
418 50 : return _mm256_and_pd(less, ones);
419 : }
420 :
421 : inline InaVecAVX isZero() const {
422 60 : const __m256d equalZero = _mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_EQ_OQ);
423 30 : const __m256d ones = _mm256_set1_pd(1);
424 30 : return _mm256_and_pd(equalZero, ones);
425 : }
426 :
427 : inline InaVecAVX isNotZero() const {
428 60 : const __m256d equalZero = _mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_NEQ_OQ);
429 30 : const __m256d ones = _mm256_set1_pd(1);
430 30 : return _mm256_and_pd(equalZero, ones);
431 : }
432 :
433 : inline InaVecMaskAVX<double> isPositiveMask() const {
434 150 : return _mm256_castpd_si256(_mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_LE_OQ));
435 : }
436 :
437 : inline InaVecMaskAVX<double> isNegativeMask() const {
438 150 : return _mm256_castpd_si256(_mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_GE_OQ));
439 : }
440 :
441 : inline InaVecMaskAVX<double> isPositiveStrictMask() const {
442 150 : return _mm256_castpd_si256(_mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_LT_OQ));
443 : }
444 :
445 : inline InaVecMaskAVX<double> isNegativeStrictMask() const {
446 150 : return _mm256_castpd_si256(_mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_GT_OQ));
447 : }
448 :
449 : inline InaVecMaskAVX<double> isZeroMask() const {
450 120 : return _mm256_castpd_si256(_mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_EQ_OQ));
451 : }
452 :
453 : inline InaVecMaskAVX<double> isNotZeroMask() const {
454 108 : return _mm256_castpd_si256(_mm256_cmp_pd(_mm256_setzero_pd(), vec, _CMP_NEQ_OQ));
455 : }
456 :
457 : // Static basic methods
458 : inline static InaVecAVX GetZero() {
459 40 : return InaVecAVX(_mm256_setzero_pd());
460 : }
461 :
462 : inline static InaVecAVX GetOne() {
463 10 : return InaVecAVX(_mm256_set1_pd(1));
464 : }
465 :
466 : inline static InaVecAVX Min(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
467 60 : return _mm256_min_pd(inVec1.vec, inVec2.vec);
468 : }
469 :
470 : inline static InaVecAVX Max(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
471 60 : return _mm256_max_pd(inVec1.vec, inVec2.vec);
472 : }
473 :
474 : inline static InaVecAVX IsLowerOrEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
475 80 : const __m256d testResult = _mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_LE_OQ);
476 40 : const __m256d ones = _mm256_set1_pd(1);
477 40 : return _mm256_and_pd(testResult, ones);
478 : }
479 :
480 : inline static InaVecAVX IsLower(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
481 80 : const __m256d testResult = _mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_LT_OQ);
482 40 : const __m256d ones = _mm256_set1_pd(1);
483 40 : return _mm256_and_pd(testResult, ones);
484 : }
485 :
486 : inline static InaVecAVX IsGreaterOrEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
487 80 : const __m256d testResult = _mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_GE_OQ);
488 40 : const __m256d ones = _mm256_set1_pd(1);
489 40 : return _mm256_and_pd(testResult, ones);
490 : }
491 :
492 : inline static InaVecAVX IsGreater(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
493 80 : const __m256d testResult = _mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_GT_OQ);
494 40 : const __m256d ones = _mm256_set1_pd(1);
495 40 : return _mm256_and_pd(testResult, ones);
496 : }
497 :
498 : inline static InaVecAVX IsEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
499 80 : const __m256d testResult = _mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_EQ_OQ);
500 40 : const __m256d ones = _mm256_set1_pd(1);
501 40 : return _mm256_and_pd(testResult, ones);
502 : }
503 :
504 : inline static InaVecAVX IsNotEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
505 80 : const __m256d testResult = _mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_NEQ_OQ);
506 40 : const __m256d ones = _mm256_set1_pd(1);
507 40 : return _mm256_and_pd(testResult, ones);
508 : }
509 :
510 : inline static InaVecMaskAVX<double> IsLowerOrEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
511 150 : return _mm256_castpd_si256(_mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_LE_OQ));
512 : }
513 :
514 : inline static InaVecMaskAVX<double> IsLowerMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
515 126 : return _mm256_castpd_si256(_mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_LT_OQ));
516 : }
517 :
518 : inline static InaVecMaskAVX<double> IsGreaterOrEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
519 144 : return _mm256_castpd_si256(_mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_GE_OQ));
520 : }
521 :
522 : inline static InaVecMaskAVX<double> IsGreaterMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
523 120 : return _mm256_castpd_si256(_mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_GT_OQ));
524 : }
525 :
526 : inline static InaVecMaskAVX<double> IsEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
527 276 : return _mm256_castpd_si256(_mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_EQ_OQ));
528 : }
529 :
530 : inline static InaVecMaskAVX<double> IsNotEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
531 186 : return _mm256_castpd_si256(_mm256_cmp_pd(inVec1.vec, inVec2.vec, _CMP_NEQ_OQ));
532 : }
533 :
534 : inline static InaVecAVX BitsAnd(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
535 60 : return _mm256_and_pd(inVec1.vec, inVec2.vec);
536 : }
537 :
538 : inline static InaVecAVX BitsNotAnd(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
539 80 : return _mm256_andnot_pd(inVec1.vec, inVec2.vec);
540 : }
541 :
542 : inline static InaVecAVX BitsOr(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
543 204 : return _mm256_or_pd(inVec1.vec, inVec2.vec);
544 : }
545 :
546 : inline static InaVecAVX BitsXor(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
547 60 : return _mm256_xor_pd(inVec1.vec, inVec2.vec);
548 : }
549 :
550 : inline static const char* GetName() {
551 : return "InaVecAVX<double>";
552 : }
553 :
554 : inline static InaIfElse< InaVecAVX<double> >::ThenClass If(const InaVecMaskAVX<double>& inTest) {
555 30 : return InaIfElse< InaVecAVX<double> >::IfClass().If(inTest);
556 : }
557 :
558 : inline static InaVecAVX IfElse(const InaVecMaskAVX<double>& inMask, const InaVecAVX& inIfTrue, const InaVecAVX& inIfFalse) {
559 16 : return _mm256_or_pd(IfTrue(inMask, inIfTrue.vec).vec,
560 32 : IfFalse(inMask, inIfFalse.vec).vec);
561 : }
562 :
563 : inline static InaVecAVX IfTrue(const InaVecMaskAVX<double>& inMask, const InaVecAVX& inIfTrue) {
564 2128 : return _mm256_and_pd(_mm256_castsi256_pd(inMask.getMask()), inIfTrue.vec);
565 : }
566 :
567 : inline static InaVecAVX IfFalse(const InaVecMaskAVX<double>& inMask, const InaVecAVX& inIfFalse) {
568 160 : return _mm256_andnot_pd(_mm256_castsi256_pd(inMask.getMask()), inIfFalse.vec);
569 : }
570 :
571 : // Inner operators
572 : inline InaVecAVX<double>& operator+=(const InaVecAVX<double>& inVec){
573 52 : vec = _mm256_add_pd(vec,inVec.vec);
574 : return *this;
575 : }
576 :
577 : inline InaVecAVX<double>& operator-=(const InaVecAVX<double>& inVec){
578 42 : vec = _mm256_sub_pd(vec,inVec.vec);
579 : return *this;
580 : }
581 :
582 : inline InaVecAVX<double>& operator/=(const InaVecAVX<double>& inVec){
583 22 : vec = _mm256_div_pd(vec,inVec.vec);
584 : return *this;
585 : }
586 :
587 : inline InaVecAVX<double>& operator*=(const InaVecAVX<double>& inVec){
588 282 : vec = _mm256_mul_pd(vec,inVec.vec);
589 : return *this;
590 : }
591 :
592 : inline InaVecAVX<double> operator-() const {
593 40 : const __m256d minus0 = _mm256_castsi256_pd(_mm256_set1_epi64x(static_cast<long long>(0x8000000000000000L)));
594 80 : return _mm256_xor_pd(vec, minus0);
595 : }
596 :
597 : inline InaVecAVX<double> pow(std::size_t power) const{
598 60 : return InaUtils::FastPow<InaVecAVX<double>>(*this, power);
599 : }
600 :
601 : // Multiple sum
602 : template <class ... Args>
603 : inline static void MultiHorizontalSum(double sumRes[], const InaVecAVX<double>& inVec1,
604 : const InaVecAVX<double>& inVec2, const InaVecAVX<double>& inVec3,
605 : const InaVecAVX<double>& inVec4, Args ...args){
606 152 : const __m256d val_a01_b01_a23_b23 = _mm256_hadd_pd(inVec1.vec, inVec2.vec);
607 152 : const __m256d val_c01_d01_c23_d23 = _mm256_hadd_pd(inVec3.vec, inVec4.vec);
608 :
609 76 : const __m256d val_a01_b01_c23_d23 = _mm256_permute2f128_pd(val_a01_b01_a23_b23, val_c01_d01_c23_d23, 0x30);// 011.0000
610 76 : const __m256d val_a23_b23_d01_d23 = _mm256_permute2f128_pd(val_a01_b01_a23_b23, val_c01_d01_c23_d23, 0x21);// 010.0001
611 :
612 76 : const __m256d val_suma_sumb_sumc_sumd = val_a01_b01_c23_d23 + val_a23_b23_d01_d23;
613 :
614 76 : __m256d vecBuffer = _mm256_loadu_pd(sumRes);
615 76 : vecBuffer += val_suma_sumb_sumc_sumd;
616 76 : _mm256_storeu_pd(sumRes, vecBuffer);
617 :
618 100 : MultiHorizontalSum(&sumRes[4], args... );
619 : }
620 :
621 : template <class ... Args>
622 80 : inline static void MultiHorizontalSum(double sumRes[], const InaVecAVX<double>& inVec1,
623 : const InaVecAVX<double>& inVec2, Args ...args){
624 1416 : const __m256d val_a01_b01_a23_b23 = _mm256_hadd_pd(inVec1.vec, inVec2.vec);
625 :
626 708 : __m128d valupper = _mm256_extractf128_pd(val_a01_b01_a23_b23, 1);
627 708 : __m128d vallower = _mm256_castpd256_pd128(val_a01_b01_a23_b23);
628 :
629 708 : __m128d vecBuffer = _mm_loadu_pd(sumRes);
630 708 : vecBuffer += valupper+vallower;
631 708 : _mm_storeu_pd(sumRes, vecBuffer);
632 :
633 798 : MultiHorizontalSum(&sumRes[2], args... );
634 80 : }
635 :
636 : inline static void MultiHorizontalSum(double sumRes[], const InaVecAVX<double>& inVec){
637 120 : sumRes[0] += inVec.horizontalSum();
638 : }
639 :
640 : inline static void MultiHorizontalSum(double /*sumRes*/[]){
641 : }
642 :
643 : inline static InaVecAVX<double> Fma(const InaVecAVX<double>& inValAdd, const InaVecAVX<double>& inValMul1, const InaVecAVX<double>& inValMul2){
644 74 : return _mm256_add_pd(inValAdd.vec, _mm256_mul_pd(inValMul1.vec,inValMul2.vec));
645 : }
646 : };
647 :
648 : // Bits operators
649 : inline InaVecAVX<double> operator&(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
650 : return InaVecAVX<double>::BitsAnd(inVec1, inVec2);
651 : }
652 :
653 : inline InaVecAVX<double> operator|(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
654 : return InaVecAVX<double>::BitsOr(inVec1, inVec2);
655 : }
656 :
657 : inline InaVecAVX<double> operator^(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
658 : return InaVecAVX<double>::BitsXor(inVec1, inVec2);
659 : }
660 :
661 : // Dual operators
662 : inline InaVecAVX<double> operator+(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
663 46 : return _mm256_add_pd(inVec1.getVec(), inVec2.getVec());
664 : }
665 :
666 : inline InaVecAVX<double> operator-(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
667 46 : return _mm256_sub_pd(inVec1.getVec(), inVec2.getVec());
668 : }
669 :
670 : inline InaVecAVX<double> operator/(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
671 26 : return _mm256_div_pd(inVec1.getVec(), inVec2.getVec());
672 : }
673 :
674 : inline InaVecAVX<double> operator*(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
675 86 : return _mm256_mul_pd(inVec1.getVec(), inVec2.getVec());
676 : }
677 :
678 : // Tests and comparions
679 : inline InaVecMaskAVX<double> operator<(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
680 2 : return InaVecAVX<double>::IsLowerMask(inVec1,inVec2);
681 : }
682 :
683 : inline InaVecMaskAVX<double> operator<=(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
684 8 : return InaVecAVX<double>::IsLowerOrEqualMask(inVec1,inVec2);
685 : }
686 :
687 : inline InaVecMaskAVX<double> operator>(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
688 : return InaVecAVX<double>::IsGreaterMask(inVec1,inVec2);
689 : }
690 :
691 : inline InaVecMaskAVX<double> operator>=(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
692 4 : return InaVecAVX<double>::IsGreaterOrEqualMask(inVec1,inVec2);
693 : }
694 :
695 : inline InaVecMaskAVX<double> operator==(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
696 50 : return InaVecAVX<double>::IsEqualMask(inVec1,inVec2);
697 : }
698 :
699 : inline InaVecMaskAVX<double> operator!=(const InaVecAVX<double>& inVec1, const InaVecAVX<double>& inVec2){
700 22 : return InaVecAVX<double>::IsNotEqualMask(inVec1,inVec2);
701 : }
702 :
703 :
704 : #endif
|