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

Generated by: LCOV version 1.13