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 INAVECSSE3FLOAT_HPP
6 : #define INAVECSSE3FLOAT_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<float> 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 InaVecMaskSSE3<float> {
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 : inline explicit operator __m128i() const{
56 : return mask;
57 : }
58 :
59 : inline __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_epi32(static_cast<int>(0xFFFFFFFF)) : _mm_setzero_si128());
66 : }
67 :
68 : inline InaVecMaskSSE3& operator=(const bool inBool){
69 : mask = (inBool? _mm_set1_epi32(static_cast<int>(0xFFFFFFFF)) : _mm_setzero_si128());
70 : return (*this);
71 : }
72 :
73 : // Binary methods
74 : inline InaVecMaskSSE3 Not() const{
75 : return NotAnd(mask, _mm_set1_epi32(static_cast<int>(0xFFFFFFFF)));
76 : }
77 :
78 : inline bool isAllTrue() const{
79 : // true if all FF
80 60 : return _mm_movemask_epi8(_mm_cmpeq_epi32(mask,_mm_set1_epi32(static_cast<int>(0xFFFFFFFF)))) == 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<float> operator&(const InaVecMaskSSE3<float>& inMask1, const InaVecMaskSSE3<float>& inMask2){
116 : return InaVecMaskSSE3<float>::And(inMask1, inMask2);
117 : }
118 :
119 : inline InaVecMaskSSE3<float> operator|(const InaVecMaskSSE3<float>& inMask1, const InaVecMaskSSE3<float>& inMask2){
120 : return InaVecMaskSSE3<float>::Or(inMask1, inMask2);
121 : }
122 :
123 : inline InaVecMaskSSE3<float> operator^(const InaVecMaskSSE3<float>& inMask1, const InaVecMaskSSE3<float>& inMask2){
124 : return InaVecMaskSSE3<float>::Xor(inMask1, inMask2);
125 : }
126 :
127 : inline bool operator==(const InaVecMaskSSE3<float>& inMask1, const InaVecMaskSSE3<float>& inMask2){
128 16 : return InaVecMaskSSE3<float>::IsEqual(inMask1, inMask2);
129 : }
130 :
131 : inline bool operator!=(const InaVecMaskSSE3<float>& inMask1, const InaVecMaskSSE3<float>& inMask2){
132 8 : return InaVecMaskSSE3<float>::IsNotEqual(inMask1, inMask2);
133 : }
134 :
135 : // Vec type
136 : template <>
137 : class InaVecSSE3<float> {
138 : protected:
139 : __m128 vec;
140 :
141 : public:
142 : using VecRawType = __m128;
143 : using MaskType = InaVecMaskSSE3<float>;
144 : using RealType = float;
145 : [[deprecated("Please use the method instead")]]
146 : static const int VecLength = 4;
147 : static const int Alignement= 16;
148 : static const bool IsOfFixedSize = true;
149 :
150 : static constexpr int GetVecLength(){
151 : return 4;
152 : }
153 :
154 : static constexpr bool IsRealFma(){
155 : #ifdef __FMA__
156 : return true;
157 : #else
158 : return false;
159 : #endif
160 : }
161 :
162 204 : inline InaVecSSE3(){}
163 : inline InaVecSSE3(const InaVecSSE3&) = default;
164 : inline InaVecSSE3& operator = (const InaVecSSE3&) = default;
165 :
166 : // Constructor from raw type
167 : /*not explicit*/ InaVecSSE3(const __m128 inVec)
168 74 : : vec(inVec){
169 : }
170 :
171 : inline InaVecSSE3& operator=(const __m128 inVec){
172 : vec = inVec;
173 : return *this;
174 : }
175 :
176 : inline void setFromRawType(const __m128 inVec){
177 : vec = inVec;
178 : }
179 :
180 : inline explicit operator __m128() const{
181 : return vec;
182 : }
183 :
184 : inline __m128 getVec() const{
185 : return vec;
186 : }
187 :
188 : // Constructor from scalar
189 : /*not explicit*/ InaVecSSE3(const float val)
190 8712 : : vec(_mm_set1_ps(val)){
191 : }
192 :
193 : inline InaVecSSE3& operator=(const float val){
194 : vec = _mm_set1_ps(val);
195 : return *this;
196 : }
197 :
198 : inline void setFromScalar(const float val){
199 : vec = _mm_set1_ps(val);
200 : }
201 :
202 : // Constructor from vec
203 : inline InaVecSSE3(const std::initializer_list<float> lst)
204 48 : : InaVecSSE3(lst.begin()){
205 : }
206 :
207 : inline explicit InaVecSSE3(const float ptr[])
208 8232 : : vec(_mm_loadu_ps(ptr)){
209 : }
210 :
211 : inline InaVecSSE3& setFromArray(const float ptr[]){
212 360 : vec = _mm_loadu_ps(ptr);
213 : return *this;
214 : }
215 :
216 : inline InaVecSSE3& setFromAlignedArray(const float ptr[]){
217 100 : vec = _mm_load_ps(ptr);
218 : return *this;
219 : }
220 :
221 : inline InaVecSSE3& setFromIndirectArray(const float values[], const int inIndirection[]) {
222 300 : vec = _mm_set_ps(
223 60 : values[inIndirection[3]],
224 60 : values[inIndirection[2]],
225 60 : values[inIndirection[1]],
226 60 : values[inIndirection[0]]);
227 : return *this;
228 : }
229 :
230 60 : inline InaVecSSE3& setFromIndirect2DArray(const float inArray[], const int inIndirection1[],
231 : const int inLeadingDimension, const int inIndirection2[]){
232 300 : vec = _mm_set_ps(
233 60 : inArray[inIndirection1[3] * inLeadingDimension + inIndirection2[3]],
234 60 : inArray[inIndirection1[2] * inLeadingDimension + inIndirection2[2]],
235 60 : inArray[inIndirection1[1] * inLeadingDimension + inIndirection2[1]],
236 60 : inArray[inIndirection1[0] * inLeadingDimension + inIndirection2[0]]);
237 60 : return *this;
238 : }
239 :
240 : // Move back to array
241 : inline void storeInArray(float ptr[]) const {
242 27704 : _mm_storeu_ps(ptr, vec);
243 : }
244 :
245 : inline void storeInAlignedArray(float ptr[]) const {
246 10360 : _mm_store_ps(ptr, vec);
247 : }
248 :
249 : // Acce to individual values
250 : inline float at(const int index) const {
251 : alignas(Alignement) float allval[GetVecLength()];
252 52320 : _mm_store_ps(allval, vec);
253 26160 : return allval[index];
254 : }
255 :
256 : // Horizontal operation
257 : inline float horizontalSum() const {
258 : // Better than _mm_hadd_ps
259 11880 : const __m128 val02_13_20_31 = _mm_add_ps(vec, _mm_movehl_ps(vec, vec));
260 7930 : const __m128 res = _mm_add_ss(val02_13_20_31, _mm_shuffle_ps(val02_13_20_31, val02_13_20_31, 1));
261 3980 : return _mm_cvtss_f32(res);
262 : }
263 :
264 : inline float horizontalMul() const {
265 160 : const __m128 val02_13_20_31 = _mm_mul_ps(vec, _mm_movehl_ps(vec, vec));
266 120 : const __m128 res = _mm_mul_ss(val02_13_20_31, _mm_shuffle_ps(val02_13_20_31, val02_13_20_31, 1));
267 60 : return _mm_cvtss_f32(res);
268 : }
269 :
270 : inline float minInVec() const {
271 480 : const __m128 val02_13_20_31 = _mm_min_ps(vec, _mm_movehl_ps(vec, vec));
272 320 : const __m128 res = _mm_min_ps(val02_13_20_31, _mm_shuffle_ps(val02_13_20_31, val02_13_20_31, 1));
273 160 : return _mm_cvtss_f32(res);
274 : }
275 :
276 : inline float maxInVec() const {
277 480 : const __m128 val02_13_20_31 = _mm_max_ps(vec, _mm_movehl_ps(vec, vec));
278 320 : const __m128 res = _mm_max_ps(val02_13_20_31, _mm_shuffle_ps(val02_13_20_31, val02_13_20_31, 1));
279 160 : return _mm_cvtss_f32(res);
280 : }
281 :
282 : inline InaVecSSE3 sqrt() const {
283 80 : return _mm_sqrt_ps(vec);
284 : }
285 :
286 34 : inline InaVecSSE3 exp() const {
287 : #ifdef __INTEL_COMPILER
288 : return _mm_exp_ps(vec);
289 : #else
290 34 : const __m128 COEFF_LOG2E = _mm_set1_ps(float(InaFastExp::CoeffLog2E()));
291 34 : const __m128 COEFF_A = _mm_set1_ps(float(InaFastExp::CoeffA32()));
292 34 : const __m128 COEFF_B = _mm_set1_ps(float(InaFastExp::CoeffB32()));
293 34 : const __m128 COEFF_P5_A = _mm_set1_ps(float(InaFastExp::GetCoefficient6_5()));
294 34 : const __m128 COEFF_P5_B = _mm_set1_ps(float(InaFastExp::GetCoefficient6_4()));
295 34 : const __m128 COEFF_P5_C = _mm_set1_ps(float(InaFastExp::GetCoefficient6_3()));
296 34 : const __m128 COEFF_P5_D = _mm_set1_ps(float(InaFastExp::GetCoefficient6_2()));
297 34 : const __m128 COEFF_P5_E = _mm_set1_ps(float(InaFastExp::GetCoefficient6_1()));
298 34 : const __m128 COEFF_P5_F = _mm_set1_ps(float(InaFastExp::GetCoefficient6_0()));
299 :
300 68 : __m128 x = _mm_mul_ps( vec , COEFF_LOG2E);
301 :
302 68 : const __m128 fractional_part = _mm_sub_ps(x, InaVecSSE3(x).floor().vec);
303 :
304 306 : __m128 factor = _mm_add_ps(_mm_mul_ps(_mm_add_ps( _mm_mul_ps(_mm_add_ps(
305 : _mm_mul_ps(_mm_add_ps( _mm_mul_ps(_mm_add_ps(_mm_mul_ps(
306 : COEFF_P5_A, fractional_part), COEFF_P5_B), fractional_part), COEFF_P5_C),fractional_part),
307 34 : COEFF_P5_D), fractional_part), COEFF_P5_E),fractional_part), COEFF_P5_F);
308 :
309 34 : x = _mm_sub_ps(x,factor);
310 :
311 102 : __m128i castedInteger = _mm_cvtps_epi32(_mm_add_ps(_mm_mul_ps(COEFF_A, x), COEFF_B));
312 :
313 34 : return _mm_castsi128_ps(castedInteger);
314 : #endif
315 : }
316 :
317 40 : inline InaVecSSE3 expLowAcc() const {
318 40 : const __m128 COEFF_LOG2E = _mm_set1_ps(float(InaFastExp::CoeffLog2E()));
319 40 : const __m128 COEFF_A = _mm_set1_ps(float(InaFastExp::CoeffA32()));
320 40 : const __m128 COEFF_B = _mm_set1_ps(float(InaFastExp::CoeffB32()));
321 40 : const __m128 COEFF_P5_D = _mm_set1_ps(float(InaFastExp::GetCoefficient3_2()));
322 40 : const __m128 COEFF_P5_E = _mm_set1_ps(float(InaFastExp::GetCoefficient3_1()));
323 40 : const __m128 COEFF_P5_F = _mm_set1_ps(float(InaFastExp::GetCoefficient3_0()));
324 :
325 80 : __m128 x = _mm_mul_ps( vec , COEFF_LOG2E);
326 :
327 80 : const __m128 fractional_part = _mm_sub_ps(x, InaVecSSE3(x).floor().vec);
328 :
329 120 : __m128 factor = _mm_add_ps(_mm_mul_ps(
330 : _mm_add_ps(_mm_mul_ps(
331 : COEFF_P5_D, fractional_part),
332 : COEFF_P5_E), fractional_part),
333 40 : COEFF_P5_F);
334 :
335 40 : x = _mm_sub_ps(x,factor);
336 :
337 120 : __m128i castedInteger = _mm_cvtps_epi32(_mm_add_ps(_mm_mul_ps(COEFF_A, x), COEFF_B));
338 :
339 40 : return _mm_castsi128_ps(castedInteger);
340 : }
341 :
342 : inline InaVecSSE3 rsqrt() const {
343 80 : return _mm_set1_ps(1) / _mm_sqrt_ps(vec); // _mm_rsqrt_ps(val); not enough accurate
344 : }
345 :
346 : inline InaVecSSE3 abs() const {
347 60 : const __m128 minus0 = _mm_castsi128_ps(_mm_set1_epi32(static_cast<int>(0x80000000)));
348 120 : return _mm_andnot_ps(minus0, vec);
349 : }
350 :
351 124 : inline InaVecSSE3 floor() const {
352 : alignas(Alignement) float allval[GetVecLength()];
353 248 : _mm_store_ps(allval, vec);
354 620 : for (int idx = 0; idx < GetVecLength(); ++idx) {
355 992 : allval[idx] = std::floor(allval[idx]);
356 : }
357 124 : return _mm_loadu_ps(allval);
358 : }
359 :
360 : inline InaVecSSE3 signOf() const {
361 100 : const __m128 minus0 = _mm_castsi128_ps(_mm_set1_epi32(static_cast<int>(0x80000000)));
362 200 : const __m128 signs = _mm_and_ps(vec, minus0);
363 400 : return _mm_andnot_ps(_mm_cmpeq_ps(_mm_setzero_ps(), vec), _mm_or_ps(signs, _mm_set1_ps(1)));
364 : }
365 :
366 : inline InaVecSSE3 isPositive() const {
367 200 : const __m128 greater = _mm_cmple_ps(_mm_setzero_ps(), vec);
368 100 : const __m128 ones = _mm_set1_ps(1);
369 100 : return _mm_and_ps(greater, ones);
370 : }
371 :
372 : inline InaVecSSE3 isNegative() const {
373 200 : const __m128 less = _mm_cmpge_ps(_mm_setzero_ps(), vec);
374 100 : const __m128 ones = _mm_set1_ps(1);
375 100 : return _mm_and_ps(less, ones);
376 : }
377 :
378 : inline InaVecSSE3 isPositiveStrict() const {
379 200 : const __m128 greater = _mm_cmplt_ps(_mm_setzero_ps(), vec);
380 100 : const __m128 ones = _mm_set1_ps(1);
381 100 : return _mm_and_ps(greater, ones);
382 : }
383 :
384 : inline InaVecSSE3 isNegativeStrict() const {
385 200 : const __m128 less = _mm_cmpgt_ps(_mm_setzero_ps(), vec);
386 100 : const __m128 ones = _mm_set1_ps(1);
387 100 : return _mm_and_ps(less, ones);
388 : }
389 :
390 : inline InaVecSSE3 isZero() const {
391 120 : const __m128 equalZero = _mm_cmpeq_ps(_mm_setzero_ps(), vec);
392 60 : const __m128 ones = _mm_set1_ps(1);
393 60 : return _mm_and_ps(equalZero, ones);
394 : }
395 :
396 : inline InaVecSSE3 isNotZero() const {
397 120 : const __m128 equalZero = _mm_cmpeq_ps(_mm_setzero_ps(), vec);
398 60 : const __m128 ones = _mm_set1_ps(1);
399 60 : return _mm_andnot_ps(equalZero, ones);
400 : }
401 :
402 : inline InaVecMaskSSE3<float> isPositiveMask() const {
403 300 : return _mm_castps_si128(_mm_cmple_ps(_mm_setzero_ps(), vec));
404 : }
405 :
406 : inline InaVecMaskSSE3<float> isNegativeMask() const {
407 300 : return _mm_castps_si128(_mm_cmpge_ps(_mm_setzero_ps(), vec));
408 : }
409 :
410 : inline InaVecMaskSSE3<float> isPositiveStrictMask() const {
411 300 : return _mm_castps_si128(_mm_cmplt_ps(_mm_setzero_ps(), vec));
412 : }
413 :
414 : inline InaVecMaskSSE3<float> isNegativeStrictMask() const {
415 300 : return _mm_castps_si128(_mm_cmpgt_ps(_mm_setzero_ps(), vec));
416 : }
417 :
418 : inline InaVecMaskSSE3<float> isZeroMask() const {
419 240 : return _mm_castps_si128(_mm_cmpeq_ps(_mm_setzero_ps(), vec));
420 : }
421 :
422 : inline InaVecMaskSSE3<float> isNotZeroMask() const {
423 216 : return _mm_castps_si128(_mm_cmpneq_ps(_mm_setzero_ps(), vec));
424 : }
425 :
426 : // Static basic methods
427 : inline static InaVecSSE3 GetZero() {
428 80 : return InaVecSSE3(_mm_setzero_ps());
429 : }
430 :
431 : inline static InaVecSSE3 GetOne() {
432 20 : return InaVecSSE3(_mm_set1_ps(1));
433 : }
434 :
435 : inline static InaVecSSE3 Min(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
436 120 : return _mm_min_ps(inVec1.vec, inVec2.vec);
437 : }
438 :
439 : inline static InaVecSSE3 Max(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
440 120 : return _mm_max_ps(inVec1.vec, inVec2.vec);
441 : }
442 :
443 : inline static InaVecSSE3 IsLowerOrEqual(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
444 160 : const __m128 testResult = _mm_cmple_ps(inVec1.vec, inVec2.vec);
445 80 : const __m128 ones = _mm_set1_ps(1);
446 80 : return _mm_and_ps(testResult, ones);
447 : }
448 :
449 : inline static InaVecSSE3 IsLower(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
450 160 : const __m128 testResult = _mm_cmplt_ps(inVec1.vec, inVec2.vec);
451 80 : const __m128 ones = _mm_set1_ps(1);
452 80 : return _mm_and_ps(testResult, ones);
453 : }
454 :
455 : inline static InaVecSSE3 IsGreaterOrEqual(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
456 160 : const __m128 testResult = _mm_cmpge_ps(inVec1.vec, inVec2.vec);
457 80 : const __m128 ones = _mm_set1_ps(1);
458 80 : return _mm_and_ps(testResult, ones);
459 : }
460 :
461 : inline static InaVecSSE3 IsGreater(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
462 160 : const __m128 testResult = _mm_cmpgt_ps(inVec1.vec, inVec2.vec);
463 80 : const __m128 ones = _mm_set1_ps(1);
464 80 : return _mm_and_ps(testResult, ones);
465 : }
466 :
467 : inline static InaVecSSE3 IsEqual(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
468 160 : const __m128 testResult = _mm_cmpeq_ps(inVec1.vec, inVec2.vec);
469 80 : const __m128 ones = _mm_set1_ps(1);
470 80 : return _mm_and_ps(testResult, ones);
471 : }
472 :
473 : inline static InaVecSSE3 IsNotEqual(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
474 160 : const __m128 testResult = _mm_cmpneq_ps(inVec1.vec, inVec2.vec);
475 80 : const __m128 ones = _mm_set1_ps(1);
476 80 : return _mm_and_ps(testResult, ones);
477 : }
478 :
479 : inline static InaVecMaskSSE3<float> IsLowerOrEqualMask(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
480 300 : return _mm_castps_si128(_mm_cmple_ps(inVec1.vec, inVec2.vec));
481 : }
482 :
483 : inline static InaVecMaskSSE3<float> IsLowerMask(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
484 252 : return _mm_castps_si128(_mm_cmplt_ps(inVec1.vec, inVec2.vec));
485 : }
486 :
487 : inline static InaVecMaskSSE3<float> IsGreaterOrEqualMask(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
488 288 : return _mm_castps_si128(_mm_cmpge_ps(inVec1.vec, inVec2.vec));
489 : }
490 :
491 : inline static InaVecMaskSSE3<float> IsGreaterMask(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
492 240 : return _mm_castps_si128(_mm_cmpgt_ps(inVec1.vec, inVec2.vec));
493 : }
494 :
495 : inline static InaVecMaskSSE3<float> IsEqualMask(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
496 548 : return _mm_castps_si128(_mm_cmpeq_ps(inVec1.vec, inVec2.vec));
497 : }
498 :
499 : inline static InaVecMaskSSE3<float> IsNotEqualMask(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
500 372 : return _mm_castps_si128(_mm_cmpneq_ps(inVec1.vec, inVec2.vec));
501 : }
502 :
503 : inline static InaVecSSE3 BitsAnd(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
504 120 : return _mm_and_ps(inVec1.vec, inVec2.vec);
505 : }
506 :
507 : inline static InaVecSSE3 BitsNotAnd(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
508 160 : return _mm_andnot_ps(inVec1.vec, inVec2.vec);
509 : }
510 :
511 : inline static InaVecSSE3 BitsOr(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
512 408 : return _mm_or_ps(inVec1.vec, inVec2.vec);
513 : }
514 :
515 : inline static InaVecSSE3 BitsXor(const InaVecSSE3& inVec1, const InaVecSSE3& inVec2) {
516 120 : return _mm_xor_ps(inVec1.vec, inVec2.vec);
517 : }
518 :
519 : inline static const char* GetName() {
520 : return "InaVecSSE3<float>";
521 : }
522 :
523 : inline static InaIfElse< InaVecSSE3<float> >::ThenClass If(const InaVecMaskSSE3<float>& inTest) {
524 30 : return InaIfElse< InaVecSSE3<float> >::IfClass().If(inTest);
525 : }
526 :
527 : inline static InaVecSSE3 IfElse(const InaVecMaskSSE3<float>& inMask, const InaVecSSE3& inIfTrue, const InaVecSSE3& inIfFalse) {
528 32 : return _mm_or_ps(IfTrue(inMask, inIfTrue.vec).vec,
529 64 : IfFalse(inMask, inIfFalse.vec).vec);
530 : }
531 :
532 : inline static InaVecSSE3 IfTrue(const InaVecMaskSSE3<float>& inMask, const InaVecSSE3& inIfTrue) {
533 4256 : return _mm_and_ps(_mm_castsi128_ps(inMask.getMask()), inIfTrue.vec);
534 : }
535 :
536 : inline static InaVecSSE3 IfFalse(const InaVecMaskSSE3<float>& inMask, const InaVecSSE3& inIfFalse) {
537 356 : return _mm_andnot_ps(_mm_castsi128_ps(inMask.getMask()), inIfFalse.vec);
538 : }
539 :
540 : // Inner operators
541 : inline InaVecSSE3<float>& operator+=(const InaVecSSE3<float>& inVec){
542 104 : vec = _mm_add_ps(vec,inVec.vec);
543 : return *this;
544 : }
545 :
546 : inline InaVecSSE3<float>& operator-=(const InaVecSSE3<float>& inVec){
547 84 : vec = _mm_sub_ps(vec,inVec.vec);
548 : return *this;
549 : }
550 :
551 : inline InaVecSSE3<float>& operator/=(const InaVecSSE3<float>& inVec){
552 44 : vec = _mm_div_ps(vec,inVec.vec);
553 : return *this;
554 : }
555 :
556 : inline InaVecSSE3<float>& operator*=(const InaVecSSE3<float>& inVec){
557 564 : vec = _mm_mul_ps(vec,inVec.vec);
558 : return *this;
559 : }
560 :
561 : inline InaVecSSE3<float> operator-() const {
562 80 : const __m128 minus0 = _mm_castsi128_ps(_mm_set1_epi32(static_cast<int>(0x80000000)));
563 160 : return _mm_xor_ps(vec, minus0);
564 : }
565 :
566 : inline InaVecSSE3<float> pow(std::size_t power) const{
567 120 : return InaUtils::FastPow<InaVecSSE3<float>>(*this, power);
568 : }
569 :
570 : // Multiple sum
571 : template <class ... Args>
572 4 : inline static void MultiHorizontalSum(float sumRes[], const InaVecSSE3<float>& inVec1,
573 : const InaVecSSE3<float>& inVec2, const InaVecSSE3<float>& inVec3,
574 : const InaVecSSE3<float>& inVec4, Args ...args){
575 152 : const __m128 val_a01_a23_b01_b23 = _mm_hadd_ps(inVec1.vec, inVec2.vec);
576 152 : const __m128 val_c01_c23_d01_d23 = _mm_hadd_ps(inVec3.vec, inVec4.vec);
577 :
578 76 : const __m128 val_suma_sumb_sumc_sumd = _mm_hadd_ps(val_a01_a23_b01_b23, val_c01_c23_d01_d23);
579 :
580 76 : __m128 vecBuffer = _mm_loadu_ps(sumRes);
581 76 : vecBuffer += val_suma_sumb_sumc_sumd;
582 76 : _mm_storeu_ps(sumRes, vecBuffer);
583 :
584 100 : MultiHorizontalSum(&sumRes[4], args... );
585 4 : }
586 :
587 : template <class ... Args>
588 1188 : inline static void MultiHorizontalSum(float sumRes[], const InaVecSSE3<float>& inVec1,
589 : const InaVecSSE3<float>& inVec2, Args ...args){
590 3136 : const __m128 val_a01_a23_b01_b23 = _mm_hadd_ps(inVec1.vec, inVec2.vec);
591 1568 : const __m128 val_a23_a01_b23_b01 = _mm_shuffle_ps(val_a01_a23_b01_b23, val_a01_a23_b01_b23, 0xB1);// 10.11.00.01
592 :
593 1568 : const __m128 val_suma_x_sumb_x = _mm_add_ps(val_a01_a23_b01_b23, val_a23_a01_b23_b01);
594 :
595 1568 : alignas(Alignement) float buffer[GetVecLength()] = {0};
596 1568 : buffer[0] = sumRes[0];
597 1568 : buffer[2] = sumRes[1];
598 1568 : __m128 vecBuffer = _mm_load_ps(buffer);
599 1568 : vecBuffer += val_suma_x_sumb_x;
600 1568 : _mm_store_ps(buffer, vecBuffer);
601 1568 : sumRes[0] = buffer[0];
602 1568 : sumRes[1] = buffer[2];
603 :
604 1758 : MultiHorizontalSum(&sumRes[2], args... );
605 1188 : }
606 :
607 : inline static void MultiHorizontalSum(float sumRes[], const InaVecSSE3<float>& inVec){
608 240 : sumRes[0] += inVec.horizontalSum();
609 : }
610 :
611 : inline static void MultiHorizontalSum(float /*sumRes*/[]){
612 : }
613 :
614 : inline static InaVecSSE3<float> Fma(const InaVecSSE3<float>& inValAdd, const InaVecSSE3<float>& inValMul1, const InaVecSSE3<float>& inValMul2){
615 : #ifdef __FMA__
616 : return _mm_fmadd_ps(inValMul1.vec, inValMul2.vec, inValAdd.vec);
617 : #else
618 148 : return _mm_add_ps(inValAdd.vec, _mm_mul_ps(inValMul1.vec,inValMul2.vec));
619 : #endif
620 : }
621 : };
622 :
623 : // Bits operators
624 : inline InaVecSSE3<float> operator&(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
625 : return InaVecSSE3<float>::BitsAnd(inVec1, inVec2);
626 : }
627 :
628 : inline InaVecSSE3<float> operator|(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
629 : return InaVecSSE3<float>::BitsOr(inVec1, inVec2);
630 : }
631 :
632 : inline InaVecSSE3<float> operator^(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
633 : return InaVecSSE3<float>::BitsXor(inVec1, inVec2);
634 : }
635 :
636 : // Dual operators
637 : inline InaVecSSE3<float> operator+(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
638 92 : return _mm_add_ps(inVec1.getVec(), inVec2.getVec());
639 : }
640 :
641 : inline InaVecSSE3<float> operator-(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
642 92 : return _mm_sub_ps(inVec1.getVec(), inVec2.getVec());
643 : }
644 :
645 : inline InaVecSSE3<float> operator/(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
646 52 : return _mm_div_ps(inVec1.getVec(), inVec2.getVec());
647 : }
648 :
649 : inline InaVecSSE3<float> operator*(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
650 172 : return _mm_mul_ps(inVec1.getVec(), inVec2.getVec());
651 : }
652 :
653 : // Tests and comparions
654 : inline InaVecMaskSSE3<float> operator<(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
655 4 : return InaVecSSE3<float>::IsLowerMask(inVec1,inVec2);
656 : }
657 :
658 : inline InaVecMaskSSE3<float> operator<=(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
659 16 : return InaVecSSE3<float>::IsLowerOrEqualMask(inVec1,inVec2);
660 : }
661 :
662 : inline InaVecMaskSSE3<float> operator>(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
663 : return InaVecSSE3<float>::IsGreaterMask(inVec1,inVec2);
664 : }
665 :
666 : inline InaVecMaskSSE3<float> operator>=(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
667 8 : return InaVecSSE3<float>::IsGreaterOrEqualMask(inVec1,inVec2);
668 : }
669 :
670 : inline InaVecMaskSSE3<float> operator==(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
671 100 : return InaVecSSE3<float>::IsEqualMask(inVec1,inVec2);
672 : }
673 :
674 : inline InaVecMaskSSE3<float> operator!=(const InaVecSSE3<float>& inVec1, const InaVecSSE3<float>& inVec2){
675 44 : return InaVecSSE3<float>::IsNotEqualMask(inVec1,inVec2);
676 : }
677 :
678 :
679 :
680 : #endif
|