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