LCOV - code coverage report
Current view: top level - Src/AVX - InaVecAVXFloat.hpp (source / functions) Hit Total Coverage
Test: Coverage inastemp Lines: 228 228 100.0 %
Date: 2022-03-17 09:48:28 Functions: 87 87 100.0 %

          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

Generated by: LCOV version 1.13