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 INAVECAVXFLOAT_HPP
6 : #define INAVECAVXFLOAT_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<float> 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<float> {
32 : __m256i mask;
33 : public:
34 : // Classic constructors
35 : inline InaVecMaskAVX(){}
36 :
37 : 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_epi32(static_cast<int>(0xFFFFFFFF)) : _mm256_setzero_si256());
60 : }
61 :
62 : inline InaVecMaskAVX& operator=(const bool inBool){
63 : mask = (inBool? _mm256_set1_epi32(static_cast<int>(0xFFFFFFFF)) : _mm256_setzero_si256());
64 : return (*this);
65 : }
66 :
67 : // Binary methods
68 : inline InaVecMaskAVX Not() const{
69 : return NotAnd(mask, _mm256_set1_epi32(static_cast<int>(0xFFFFFFFF)));
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_epi32(static_cast<int>(0xFFFFFFFF)));
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_castps_si256(_mm256_and_ps(_mm256_castsi256_ps(inMask1.mask),
86 : _mm256_castsi256_ps(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_castps_si256(_mm256_andnot_ps(_mm256_castsi256_ps(inMask1.mask),
92 : _mm256_castsi256_ps(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_castps_si256(_mm256_or_ps(_mm256_castsi256_ps(inMask1.mask),
98 48 : _mm256_castsi256_ps(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_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(inMask1.mask),
104 : _mm256_castsi256_ps(inMask2.mask))));
105 : }
106 :
107 : inline static bool IsEqual(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
108 40 : return _mm256_testz_si256(_mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(inMask1.mask),
109 8 : _mm256_castsi256_ps(inMask2.mask))),
110 8 : _mm256_set1_epi32(static_cast<int>(0xFFFFFFFF))); // return CF
111 : }
112 :
113 : inline static bool IsNotEqual(const InaVecMaskAVX& inMask1, const InaVecMaskAVX& inMask2){
114 20 : return !_mm256_testz_si256(_mm256_castps_si256(_mm256_xor_ps(_mm256_castsi256_ps(inMask1.mask),
115 4 : _mm256_castsi256_ps(inMask2.mask))),
116 4 : _mm256_set1_epi32(static_cast<int>(0xFFFFFFFF))); // return CF
117 : }
118 : };
119 :
120 : // Mask must have operators
121 : inline InaVecMaskAVX<float> operator&(const InaVecMaskAVX<float>& inMask1, const InaVecMaskAVX<float>& inMask2){
122 : return InaVecMaskAVX<float>::And(inMask1, inMask2);
123 : }
124 :
125 : inline InaVecMaskAVX<float> operator|(const InaVecMaskAVX<float>& inMask1, const InaVecMaskAVX<float>& inMask2){
126 : return InaVecMaskAVX<float>::Or(inMask1, inMask2);
127 : }
128 :
129 : inline InaVecMaskAVX<float> operator^(const InaVecMaskAVX<float>& inMask1, const InaVecMaskAVX<float>& inMask2){
130 : return InaVecMaskAVX<float>::Xor(inMask1, inMask2);
131 : }
132 :
133 : inline bool operator==(const InaVecMaskAVX<float>& inMask1, const InaVecMaskAVX<float>& inMask2){
134 8 : return InaVecMaskAVX<float>::IsEqual(inMask1, inMask2);
135 : }
136 :
137 : inline bool operator!=(const InaVecMaskAVX<float>& inMask1, const InaVecMaskAVX<float>& inMask2){
138 4 : return InaVecMaskAVX<float>::IsNotEqual(inMask1, inMask2);
139 : }
140 :
141 : // Vec type
142 : template <>
143 : class alignas(32) InaVecAVX<float> {
144 : protected:
145 : __m256 vec;
146 :
147 : public:
148 : using VecRawType = __m256;
149 : using MaskType = InaVecMaskAVX<float>;
150 : using RealType = float;
151 : [[deprecated("Please use the method instead")]]
152 : static const int VecLength = 8;
153 : static const int Alignement= 32;
154 : static const bool IsOfFixedSize = true;
155 :
156 : static constexpr int GetVecLength(){
157 : return 8;
158 : }
159 :
160 : static constexpr bool IsRealFma(){
161 : return false;
162 : }
163 :
164 119 : 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 __m256 inVec)
170 : : vec(inVec){
171 : }
172 :
173 : inline InaVecAVX& operator=(const __m256 inVec){
174 : vec = inVec;
175 : return *this;
176 : }
177 :
178 : inline void setFromRawType(const __m256 inVec){
179 : vec = inVec;
180 : }
181 :
182 : inline explicit operator __m256() const{
183 : return vec;
184 : }
185 :
186 : inline __m256 getVec() const{
187 : return vec;
188 : }
189 :
190 : // Constructor from scalar
191 : inline /*not explicit*/ InaVecAVX(const float val)
192 4746 : : vec(_mm256_set1_ps(val)){
193 : }
194 :
195 : inline InaVecAVX& operator=(const float val){
196 : vec = _mm256_set1_ps(val);
197 : return *this;
198 : }
199 :
200 : inline void setFromScalar(const float val){
201 : vec = _mm256_set1_ps(val);
202 : }
203 :
204 : // Constructor from vec
205 : inline InaVecAVX(const std::initializer_list<float> lst)
206 24 : : InaVecAVX(lst.begin()){
207 : }
208 :
209 : inline explicit InaVecAVX(const float ptr[])
210 4596 : : vec(_mm256_loadu_ps(ptr)){
211 : }
212 :
213 : inline InaVecAVX& setFromArray(const float ptr[]){
214 340 : vec = _mm256_loadu_ps(ptr);
215 : return *this;
216 : }
217 :
218 : inline InaVecAVX& setFromAlignedArray(const float ptr[]){
219 50 : vec = _mm256_load_ps(ptr);
220 : return *this;
221 : }
222 :
223 30 : inline InaVecAVX& setFromIndirectArray(const float values[], const int inIndirection[]) {
224 270 : vec = _mm256_set_ps(
225 30 : values[inIndirection[7]],
226 30 : values[inIndirection[6]],
227 30 : values[inIndirection[5]],
228 30 : values[inIndirection[4]],
229 30 : values[inIndirection[3]],
230 30 : values[inIndirection[2]],
231 30 : values[inIndirection[1]],
232 30 : values[inIndirection[0]]);
233 30 : return *this;
234 : }
235 :
236 30 : inline InaVecAVX& setFromIndirect2DArray(const float inArray[], const int inIndirection1[],
237 : const int inLeadingDimension, const int inIndirection2[]){
238 270 : vec = _mm256_set_ps(
239 30 : inArray[inIndirection1[7] * inLeadingDimension + inIndirection2[7]],
240 30 : inArray[inIndirection1[6] * inLeadingDimension + inIndirection2[6]],
241 30 : inArray[inIndirection1[5] * inLeadingDimension + inIndirection2[5]],
242 30 : inArray[inIndirection1[4] * inLeadingDimension + inIndirection2[4]],
243 30 : inArray[inIndirection1[3] * inLeadingDimension + inIndirection2[3]],
244 30 : inArray[inIndirection1[2] * inLeadingDimension + inIndirection2[2]],
245 30 : inArray[inIndirection1[1] * inLeadingDimension + inIndirection2[1]],
246 30 : inArray[inIndirection1[0] * inLeadingDimension + inIndirection2[0]]);
247 30 : return *this;
248 : }
249 :
250 : // Move back to array
251 : inline void storeInArray(float ptr[]) const {
252 30892 : _mm256_storeu_ps(ptr, vec);
253 : }
254 :
255 : inline void storeInAlignedArray(float ptr[]) const {
256 6220 : _mm256_store_ps(ptr, vec);
257 : }
258 :
259 : // Acce to individual values
260 : inline float at(const int index) const {
261 : alignas(Alignement) float allval[GetVecLength()];
262 60640 : _mm256_store_ps(allval, vec);
263 30320 : return allval[index];
264 : }
265 :
266 : // Horizontal operation
267 : inline float horizontalSum() const {
268 3972 : const __m128 valupper = _mm256_extractf128_ps(vec, 1);
269 3972 : const __m128 rest = _mm256_extractf128_ps(vec, 0);
270 : const __m128 valval = _mm_add_ps(valupper,
271 1990 : rest);
272 3972 : __m128 valsum = _mm_add_ps(_mm_permute_ps(valval, 0x1B), valval);
273 3972 : __m128 res = _mm_add_ps(_mm_permute_ps(valsum, 0xB1), valsum);
274 1990 : return _mm_cvtss_f32(res);
275 : }
276 :
277 : inline float horizontalMul() const {
278 60 : const __m128 valupper = _mm256_extractf128_ps(vec, 1);
279 60 : const __m128 rest = _mm256_extractf128_ps(vec, 0);
280 : const __m128 valval = _mm_mul_ps(valupper,
281 30 : rest);
282 60 : __m128 valsum = _mm_mul_ps(_mm_permute_ps(valval, 0x1B), valval);
283 60 : __m128 res = _mm_mul_ps(_mm_permute_ps(valsum, 0xB1), valsum);
284 30 : return _mm_cvtss_f32(res);
285 : }
286 :
287 :
288 : inline float minInVec() const {
289 320 : const __m128 valupper = _mm256_extractf128_ps(vec, 1);
290 320 : const __m128 rest = _mm256_extractf128_ps(vec, 0);
291 : const __m128 valval = _mm_min_ps(valupper,
292 160 : rest);
293 320 : __m128 valsum = _mm_min_ps(_mm_permute_ps(valval, 0x1B), valval);
294 320 : __m128 res = _mm_min_ps(_mm_permute_ps(valsum, 0xB1), valsum);
295 160 : return _mm_cvtss_f32(res);
296 : }
297 :
298 : inline float maxInVec() const {
299 320 : const __m128 valupper = _mm256_extractf128_ps(vec, 1);
300 320 : const __m128 rest = _mm256_extractf128_ps(vec, 0);
301 : const __m128 valval = _mm_max_ps(valupper,
302 160 : rest);
303 320 : __m128 valsum = _mm_max_ps(_mm_permute_ps(valval, 0x1B), valval);
304 320 : __m128 res = _mm_max_ps(_mm_permute_ps(valsum, 0xB1), valsum);
305 160 : return _mm_cvtss_f32(res);
306 : }
307 :
308 : inline InaVecAVX sqrt() const {
309 40 : return _mm256_sqrt_ps(vec);
310 : }
311 :
312 30 : inline InaVecAVX exp() const {
313 : #ifdef __INTEL_COMPILER
314 : return _mm256_exp_ps(vec);
315 : #else
316 30 : const __m256 COEFF_LOG2E = _mm256_set1_ps(float(InaFastExp::CoeffLog2E()));
317 30 : const __m256 COEFF_A = _mm256_set1_ps(float(InaFastExp::CoeffA32()));
318 30 : const __m256 COEFF_B = _mm256_set1_ps(float(InaFastExp::CoeffB32()));
319 30 : const __m256 COEFF_P5_A = _mm256_set1_ps(float(InaFastExp::GetCoefficient6_5()));
320 30 : const __m256 COEFF_P5_B = _mm256_set1_ps(float(InaFastExp::GetCoefficient6_4()));
321 30 : const __m256 COEFF_P5_C = _mm256_set1_ps(float(InaFastExp::GetCoefficient6_3()));
322 30 : const __m256 COEFF_P5_D = _mm256_set1_ps(float(InaFastExp::GetCoefficient6_2()));
323 30 : const __m256 COEFF_P5_E = _mm256_set1_ps(float(InaFastExp::GetCoefficient6_1()));
324 30 : const __m256 COEFF_P5_F = _mm256_set1_ps(float(InaFastExp::GetCoefficient6_0()));
325 :
326 60 : __m256 x = _mm256_mul_ps(vec, COEFF_LOG2E);
327 :
328 90 : const __m256 fractional_part = _mm256_sub_ps(x, InaVecAVX(x).floor().vec);
329 :
330 270 : __m256 factor = _mm256_add_ps(_mm256_mul_ps(_mm256_add_ps( _mm256_mul_ps(_mm256_add_ps(
331 : _mm256_mul_ps(_mm256_add_ps( _mm256_mul_ps(_mm256_add_ps(_mm256_mul_ps(
332 : COEFF_P5_A, fractional_part), COEFF_P5_B), fractional_part), COEFF_P5_C),fractional_part),
333 30 : COEFF_P5_D), fractional_part), COEFF_P5_E),fractional_part), COEFF_P5_F);
334 :
335 30 : x = _mm256_sub_ps(x,factor);
336 :
337 90 : __m256i castedInteger = _mm256_cvtps_epi32(_mm256_add_ps(_mm256_mul_ps(COEFF_A, x), COEFF_B));
338 :
339 30 : return _mm256_castsi256_ps(castedInteger);
340 : #endif
341 : }
342 :
343 : inline InaVecAVX expLowAcc() const {
344 20 : const __m256 COEFF_LOG2E = _mm256_set1_ps(float(InaFastExp::CoeffLog2E()));
345 20 : const __m256 COEFF_A = _mm256_set1_ps(float(InaFastExp::CoeffA32()));
346 20 : const __m256 COEFF_B = _mm256_set1_ps(float(InaFastExp::CoeffB32()));
347 20 : const __m256 COEFF_P5_D = _mm256_set1_ps(float(InaFastExp::GetCoefficient3_2()));
348 20 : const __m256 COEFF_P5_E = _mm256_set1_ps(float(InaFastExp::GetCoefficient3_1()));
349 20 : const __m256 COEFF_P5_F = _mm256_set1_ps(float(InaFastExp::GetCoefficient3_0()));
350 :
351 40 : __m256 x = _mm256_mul_ps(vec, COEFF_LOG2E);
352 :
353 60 : const __m256 fractional_part = _mm256_sub_ps(x, InaVecAVX(x).floor().vec);
354 :
355 60 : __m256 factor = _mm256_add_ps(_mm256_mul_ps(
356 : _mm256_add_ps(_mm256_mul_ps(
357 : COEFF_P5_D, fractional_part),
358 : COEFF_P5_E), fractional_part),
359 20 : COEFF_P5_F);
360 :
361 20 : x = _mm256_sub_ps(x,factor);
362 :
363 60 : __m256i castedInteger = _mm256_cvtps_epi32(_mm256_add_ps(_mm256_mul_ps(COEFF_A, x), COEFF_B));
364 :
365 20 : return _mm256_castsi256_ps(castedInteger);
366 : }
367 :
368 : inline InaVecAVX rsqrt() const {
369 40 : return _mm256_set1_ps(1) / _mm256_sqrt_ps(vec); // _mm256_rsqrt_ps(val); not accurate enough
370 : }
371 :
372 : inline InaVecAVX abs() const {
373 30 : const __m256 minus0 = _mm256_castsi256_ps(_mm256_set1_epi32(static_cast<int>(0x80000000)));
374 60 : return _mm256_andnot_ps(minus0, vec);
375 : }
376 :
377 : inline InaVecAVX floor() const {
378 200 : return _mm256_floor_ps(vec);
379 : }
380 :
381 : inline InaVecAVX signOf() const {
382 50 : const __m256 minus0 = _mm256_castsi256_ps(_mm256_set1_epi32(static_cast<int>(0x80000000)));
383 100 : const __m256 signs = _mm256_and_ps(vec, minus0);
384 : return _mm256_and_ps(_mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_NEQ_OQ),
385 200 : _mm256_or_ps(signs, _mm256_set1_ps(1)));
386 : }
387 :
388 : inline InaVecAVX isPositive() const {
389 100 : const __m256 greater = _mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_LE_OQ);
390 50 : const __m256 ones = _mm256_set1_ps(1);
391 50 : return _mm256_and_ps(greater, ones);
392 : }
393 :
394 : inline InaVecAVX isNegative() const {
395 100 : const __m256 less = _mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_GE_OQ);
396 50 : const __m256 ones = _mm256_set1_ps(1);
397 50 : return _mm256_and_ps(less, ones);
398 : }
399 :
400 : inline InaVecAVX isPositiveStrict() const {
401 100 : const __m256 greater = _mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_LT_OQ);
402 50 : const __m256 ones = _mm256_set1_ps(1);
403 50 : return _mm256_and_ps(greater, ones);
404 : }
405 :
406 : inline InaVecAVX isNegativeStrict() const {
407 100 : const __m256 less = _mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_GT_OQ);
408 50 : const __m256 ones = _mm256_set1_ps(1);
409 50 : return _mm256_and_ps(less, ones);
410 : }
411 :
412 : inline InaVecAVX isZero() const {
413 60 : const __m256 equalZero = _mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_EQ_OQ);
414 30 : const __m256 ones = _mm256_set1_ps(1);
415 30 : return _mm256_and_ps(equalZero, ones);
416 : }
417 :
418 : inline InaVecAVX isNotZero() const {
419 60 : const __m256 equalZero = _mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_NEQ_OQ);
420 30 : const __m256 ones = _mm256_set1_ps(1);
421 30 : return _mm256_and_ps(equalZero, ones);
422 : }
423 :
424 : inline InaVecMaskAVX<float> isPositiveMask() const {
425 150 : return _mm256_castps_si256(_mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_LE_OQ));
426 : }
427 :
428 : inline InaVecMaskAVX<float> isNegativeMask() const {
429 150 : return _mm256_castps_si256(_mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_GE_OQ));
430 : }
431 :
432 : inline InaVecMaskAVX<float> isPositiveStrictMask() const {
433 150 : return _mm256_castps_si256(_mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_LT_OQ));
434 : }
435 :
436 : inline InaVecMaskAVX<float> isNegativeStrictMask() const {
437 150 : return _mm256_castps_si256(_mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_GT_OQ));
438 : }
439 :
440 : inline InaVecMaskAVX<float> isZeroMask() const {
441 120 : return _mm256_castps_si256(_mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_EQ_OQ));
442 : }
443 :
444 : inline InaVecMaskAVX<float> isNotZeroMask() const {
445 108 : return _mm256_castps_si256(_mm256_cmp_ps(_mm256_setzero_ps(), vec, _CMP_NEQ_OQ));
446 : }
447 :
448 : // Static basic methods
449 : inline static InaVecAVX GetZero() {
450 40 : return InaVecAVX(_mm256_setzero_ps());
451 : }
452 :
453 : inline static InaVecAVX GetOne() {
454 10 : return InaVecAVX(_mm256_set1_ps(1));
455 : }
456 :
457 : inline static InaVecAVX Min(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
458 60 : return _mm256_min_ps(inVec1.vec, inVec2.vec);
459 : }
460 :
461 : inline static InaVecAVX Max(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
462 60 : return _mm256_max_ps(inVec1.vec, inVec2.vec);
463 : }
464 :
465 : inline static InaVecAVX IsLowerOrEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
466 80 : const __m256 testResult = _mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_LE_OQ);
467 40 : const __m256 ones = _mm256_set1_ps(1);
468 40 : return _mm256_and_ps(testResult, ones);
469 : }
470 :
471 : inline static InaVecAVX IsLower(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
472 80 : const __m256 testResult = _mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_LT_OQ);
473 40 : const __m256 ones = _mm256_set1_ps(1);
474 40 : return _mm256_and_ps(testResult, ones);
475 : }
476 :
477 : inline static InaVecAVX IsGreaterOrEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
478 80 : const __m256 testResult = _mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_GE_OQ);
479 40 : const __m256 ones = _mm256_set1_ps(1);
480 40 : return _mm256_and_ps(testResult, ones);
481 : }
482 :
483 : inline static InaVecAVX IsGreater(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
484 80 : const __m256 testResult = _mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_GT_OQ);
485 40 : const __m256 ones = _mm256_set1_ps(1);
486 40 : return _mm256_and_ps(testResult, ones);
487 : }
488 :
489 : inline static InaVecAVX IsEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
490 80 : const __m256 testResult = _mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_EQ_OQ);
491 40 : const __m256 ones = _mm256_set1_ps(1);
492 40 : return _mm256_and_ps(testResult, ones);
493 : }
494 :
495 : inline static InaVecAVX IsNotEqual(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
496 80 : const __m256 testResult = _mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_NEQ_OQ);
497 40 : const __m256 ones = _mm256_set1_ps(1);
498 40 : return _mm256_and_ps(testResult, ones);
499 : }
500 :
501 : inline static InaVecMaskAVX<float> IsLowerOrEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
502 150 : return _mm256_castps_si256(_mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_LE_OQ));
503 : }
504 :
505 : inline static InaVecMaskAVX<float> IsLowerMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
506 126 : return _mm256_castps_si256(_mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_LT_OQ));
507 : }
508 :
509 : inline static InaVecMaskAVX<float> IsGreaterOrEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
510 144 : return _mm256_castps_si256(_mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_GE_OQ));
511 : }
512 :
513 : inline static InaVecMaskAVX<float> IsGreaterMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
514 120 : return _mm256_castps_si256(_mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_GT_OQ));
515 : }
516 :
517 : inline static InaVecMaskAVX<float> IsEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
518 276 : return _mm256_castps_si256(_mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_EQ_OQ));
519 : }
520 :
521 : inline static InaVecMaskAVX<float> IsNotEqualMask(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
522 186 : return _mm256_castps_si256(_mm256_cmp_ps(inVec1.vec, inVec2.vec, _CMP_NEQ_OQ));
523 : }
524 :
525 : inline static InaVecAVX BitsAnd(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
526 60 : return _mm256_and_ps(inVec1.vec, inVec2.vec);
527 : }
528 :
529 : inline static InaVecAVX BitsNotAnd(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
530 80 : return _mm256_andnot_ps(inVec1.vec, inVec2.vec);
531 : }
532 :
533 : inline static InaVecAVX BitsOr(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
534 204 : return _mm256_or_ps(inVec1.vec, inVec2.vec);
535 : }
536 :
537 : inline static InaVecAVX BitsXor(const InaVecAVX& inVec1, const InaVecAVX& inVec2) {
538 60 : return _mm256_xor_ps(inVec1.vec, inVec2.vec);
539 : }
540 :
541 : inline static const char* GetName() {
542 : return "InaVecAVX<float>";
543 : }
544 :
545 : inline static InaIfElse< InaVecAVX<float> >::ThenClass If(const InaVecMaskAVX<float>& inTest) {
546 30 : return InaIfElse< InaVecAVX<float> >::IfClass().If(inTest);
547 : }
548 :
549 : inline static InaVecAVX IfElse(const InaVecMaskAVX<float>& inMask, const InaVecAVX& inIfTrue, const InaVecAVX& inIfFalse) {
550 16 : return _mm256_or_ps(IfTrue(inMask, inIfTrue.vec).vec,
551 32 : IfFalse(inMask, inIfFalse.vec).vec);
552 : }
553 :
554 : inline static InaVecAVX IfTrue(const InaVecMaskAVX<float>& inMask, const InaVecAVX& inIfTrue) {
555 2128 : return _mm256_and_ps(_mm256_castsi256_ps(inMask.getMask()), inIfTrue.vec);
556 : }
557 :
558 : inline static InaVecAVX IfFalse(const InaVecMaskAVX<float>& inMask, const InaVecAVX& inIfFalse) {
559 160 : return _mm256_andnot_ps(_mm256_castsi256_ps(inMask.getMask()), inIfFalse.vec);
560 : }
561 :
562 : // Inner operators
563 : inline InaVecAVX<float>& operator+=(const InaVecAVX<float>& inVec){
564 52 : vec = _mm256_add_ps(vec,inVec.vec);
565 : return *this;
566 : }
567 :
568 : inline InaVecAVX<float>& operator-=(const InaVecAVX<float>& inVec){
569 42 : vec = _mm256_sub_ps(vec,inVec.vec);
570 : return *this;
571 : }
572 :
573 : inline InaVecAVX<float>& operator/=(const InaVecAVX<float>& inVec){
574 22 : vec = _mm256_div_ps(vec,inVec.vec);
575 : return *this;
576 : }
577 :
578 : inline InaVecAVX<float>& operator*=(const InaVecAVX<float>& inVec){
579 282 : vec = _mm256_mul_ps(vec,inVec.vec);
580 : return *this;
581 : }
582 :
583 : inline InaVecAVX<float> operator-() const {
584 40 : const __m256 minus0 = _mm256_castsi256_ps(_mm256_set1_epi32(static_cast<int>(0x80000000)));
585 80 : return _mm256_xor_ps(vec, minus0);
586 : }
587 :
588 : inline InaVecAVX<float> pow(std::size_t power) const{
589 60 : return InaUtils::FastPow<InaVecAVX<float>>(*this, power);
590 : }
591 :
592 : // Multiple sum
593 : template <class ... Args>
594 8 : inline static void MultiHorizontalSum(float sumRes[], const InaVecAVX<float>& inVec1,
595 : const InaVecAVX<float>& inVec2, const InaVecAVX<float>& inVec3,
596 : const InaVecAVX<float>& inVec4, const InaVecAVX<float>& inVec5,
597 : const InaVecAVX<float>& inVec6, const InaVecAVX<float>& inVec7,
598 : const InaVecAVX<float>& inVec8, Args ...args){
599 56 : const __m256 val_a01_a23_b01_b23_a45_a67_b45_b67 = _mm256_hadd_ps(inVec1.vec, inVec2.vec);
600 56 : const __m256 val_c01_c23_d01_d23_c45_c67_d45_d67 = _mm256_hadd_ps(inVec3.vec, inVec4.vec);
601 :
602 56 : const __m256 val_e01_e23_f01_f23_e45_e67_f45_f67 = _mm256_hadd_ps(inVec5.vec, inVec6.vec);
603 56 : const __m256 val_g01_g23_h01_h23_g45_g67_h45_h67 = _mm256_hadd_ps(inVec7.vec, inVec8.vec);
604 :
605 28 : const __m256 val_a0123_b01b23_c0123_d01b23_a4567_b4567_c4567_d4567 = _mm256_hadd_ps(val_a01_a23_b01_b23_a45_a67_b45_b67,
606 : val_c01_c23_d01_d23_c45_c67_d45_d67);
607 :
608 28 : const __m256 val_e0123_f01b23_g0123_h01b23_e4567_f4567_g4567_h4567 = _mm256_hadd_ps(val_e01_e23_f01_f23_e45_e67_f45_f67,
609 : val_g01_g23_h01_h23_g45_g67_h45_h67);
610 :
611 28 : const __m256 val_a0123_b01b23_c0123_d01b23_e0123_f01b23_g0123_h01b23 =
612 : _mm256_permute2f128_ps(val_a0123_b01b23_c0123_d01b23_a4567_b4567_c4567_d4567,
613 : val_e0123_f01b23_g0123_h01b23_e4567_f4567_g4567_h4567, 0x20);// 010.0000
614 28 : const __m256 val_a4567_b4567_c4567_d4567_e4567_f4567_g4567_h4567 =
615 : _mm256_permute2f128_ps(val_a0123_b01b23_c0123_d01b23_a4567_b4567_c4567_d4567,
616 : val_e0123_f01b23_g0123_h01b23_e4567_f4567_g4567_h4567, 0x31);// 000.0001
617 :
618 28 : const __m256 sum_a_b_c_d_e_f_g_h = val_a0123_b01b23_c0123_d01b23_e0123_f01b23_g0123_h01b23 + val_a4567_b4567_c4567_d4567_e4567_f4567_g4567_h4567;
619 :
620 28 : __m256 vecBuffer = _mm256_loadu_ps(sumRes);
621 28 : vecBuffer += sum_a_b_c_d_e_f_g_h;
622 28 : _mm256_storeu_ps(sumRes, vecBuffer);
623 :
624 44 : MultiHorizontalSum(&sumRes[8], args... );
625 8 : }
626 :
627 : template <class ... Args>
628 : inline static void MultiHorizontalSum(float sumRes[], const InaVecAVX<float>& inVec1,
629 : const InaVecAVX<float>& inVec2, const InaVecAVX<float>& inVec3,
630 : const InaVecAVX<float>& inVec4, Args ...args){
631 40 : const __m256 val_a01_a23_b01_b23_a45_a67_b45_b67 = _mm256_hadd_ps(inVec1.vec, inVec2.vec);
632 40 : const __m256 val_c01_c23_d01_d23_c45_c67_d45_d67 = _mm256_hadd_ps(inVec3.vec, inVec4.vec);
633 :
634 20 : const __m256 val_a0123_b01b23_c0123_d01b23_a4567_b4567_c4567_d4567 = _mm256_hadd_ps(val_a01_a23_b01_b23_a45_a67_b45_b67,
635 : val_c01_c23_d01_d23_c45_c67_d45_d67);
636 :
637 20 : __m128 valupper = _mm256_extractf128_ps(val_a0123_b01b23_c0123_d01b23_a4567_b4567_c4567_d4567, 1);
638 20 : __m128 vallower = _mm256_castps256_ps128(val_a0123_b01b23_c0123_d01b23_a4567_b4567_c4567_d4567);
639 :
640 20 : __m128 vecBuffer = _mm_loadu_ps(sumRes);
641 20 : vecBuffer += valupper + vallower;
642 20 : _mm_storeu_ps(sumRes, vecBuffer);
643 :
644 30 : MultiHorizontalSum(&sumRes[4], args... );
645 : }
646 :
647 : template <class ... Args>
648 618 : inline static void MultiHorizontalSum(float sumRes[], const InaVecAVX<float>& inVec1,
649 : const InaVecAVX<float>& inVec2, Args ...args){
650 :
651 1416 : const __m256 val_a01_a23_b01_b23_a45_a67_b45_b67 = _mm256_hadd_ps(inVec1.vec, inVec2.vec);
652 :
653 708 : const __m128 valupper = _mm256_extractf128_ps(val_a01_a23_b01_b23_a45_a67_b45_b67, 1);
654 708 : const __m128 vallower = _mm256_castps256_ps128(val_a01_a23_b01_b23_a45_a67_b45_b67);
655 :
656 708 : const __m128 val_a0123_b0123_a4567_b4567 = _mm_hadd_ps(valupper, vallower);
657 :
658 708 : const __m128 val_a4567_b4567_a0123_b0123 = _mm_shuffle_ps(val_a0123_b0123_a4567_b4567, val_a0123_b0123_a4567_b4567, 0x9E);// 10.01.11.10
659 :
660 708 : const __m128 val_suma_x_sumb_x = _mm_add_ps(val_a0123_b0123_a4567_b4567, val_a4567_b4567_a0123_b0123);
661 :
662 708 : alignas(Alignement) float buffer[GetVecLength()] = {0};
663 708 : buffer[0] = sumRes[0];
664 708 : buffer[1] = sumRes[1];
665 708 : __m128 vecBuffer = _mm_load_ps(buffer);
666 708 : vecBuffer += val_suma_x_sumb_x;
667 708 : _mm_store_ps(buffer, vecBuffer);
668 708 : sumRes[0] = buffer[0];
669 708 : sumRes[1] = buffer[1];
670 :
671 798 : MultiHorizontalSum(&sumRes[2], args... );
672 618 : }
673 :
674 : inline static void MultiHorizontalSum(float sumRes[], const InaVecAVX<float>& inVec){
675 120 : sumRes[0] += inVec.horizontalSum();
676 : }
677 :
678 : inline static void MultiHorizontalSum(float /*sumRes*/[]){
679 : }
680 :
681 : inline static InaVecAVX<float> Fma(const InaVecAVX<float>& inValAdd, const InaVecAVX<float>& inValMul1, const InaVecAVX<float>& inValMul2){
682 74 : return _mm256_add_ps(inValAdd.vec, _mm256_mul_ps(inValMul1.vec,inValMul2.vec));
683 : }
684 : };
685 :
686 : // Bits operators
687 : inline InaVecAVX<float> operator&(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
688 : return InaVecAVX<float>::BitsAnd(inVec1, inVec2);
689 : }
690 :
691 : inline InaVecAVX<float> operator|(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
692 : return InaVecAVX<float>::BitsOr(inVec1, inVec2);
693 : }
694 :
695 : inline InaVecAVX<float> operator^(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
696 : return InaVecAVX<float>::BitsXor(inVec1, inVec2);
697 : }
698 :
699 : // Dual operators
700 : inline InaVecAVX<float> operator+(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
701 46 : return _mm256_add_ps(inVec1.getVec(), inVec2.getVec());
702 : }
703 :
704 : inline InaVecAVX<float> operator-(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
705 46 : return _mm256_sub_ps(inVec1.getVec(), inVec2.getVec());
706 : }
707 :
708 : inline InaVecAVX<float> operator/(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
709 26 : return _mm256_div_ps(inVec1.getVec(), inVec2.getVec());
710 : }
711 :
712 : inline InaVecAVX<float> operator*(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
713 86 : return _mm256_mul_ps(inVec1.getVec(), inVec2.getVec());
714 : }
715 :
716 : // Tests and comparions
717 : inline InaVecMaskAVX<float> operator<(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
718 2 : return InaVecAVX<float>::IsLowerMask(inVec1,inVec2);
719 : }
720 :
721 : inline InaVecMaskAVX<float> operator<=(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
722 8 : return InaVecAVX<float>::IsLowerOrEqualMask(inVec1,inVec2);
723 : }
724 :
725 : inline InaVecMaskAVX<float> operator>(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
726 : return InaVecAVX<float>::IsGreaterMask(inVec1,inVec2);
727 : }
728 :
729 : inline InaVecMaskAVX<float> operator>=(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
730 4 : return InaVecAVX<float>::IsGreaterOrEqualMask(inVec1,inVec2);
731 : }
732 :
733 : inline InaVecMaskAVX<float> operator==(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
734 50 : return InaVecAVX<float>::IsEqualMask(inVec1,inVec2);
735 : }
736 :
737 : inline InaVecMaskAVX<float> operator!=(const InaVecAVX<float>& inVec1, const InaVecAVX<float>& inVec2){
738 22 : return InaVecAVX<float>::IsNotEqualMask(inVec1,inVec2);
739 : }
740 :
741 :
742 : #endif
|