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

Generated by: LCOV version 1.13