LCOV - code coverage report
Current view: top level - gcore - gdalsse_priv.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 399 403 99.0 %
Date: 2024-05-03 15:49:35 Functions: 71 71 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  GDAL
       5             :  * Purpose:  SSE2 helper
       6             :  * Author:   Even Rouault <even dot rouault at spatialys dot com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #ifndef GDALSSE_PRIV_H_INCLUDED
      31             : #define GDALSSE_PRIV_H_INCLUDED
      32             : 
      33             : #ifndef DOXYGEN_SKIP
      34             : 
      35             : #include "cpl_port.h"
      36             : 
      37             : /* We restrict to 64bit processors because they are guaranteed to have SSE2 */
      38             : /* Could possibly be used too on 32bit, but we would need to check at runtime */
      39             : #if (defined(__x86_64) || defined(_M_X64) || defined(USE_SSE2)) &&             \
      40             :     !defined(USE_SSE2_EMULATION)
      41             : 
      42             : /* Requires SSE2 */
      43             : #include <emmintrin.h>
      44             : #include <string.h>
      45             : 
      46             : #ifdef __SSE4_1__
      47             : #include <smmintrin.h>
      48             : #endif
      49             : 
      50             : #include "gdal_priv_templates.hpp"
      51             : 
      52      523196 : static inline __m128i GDALCopyInt16ToXMM(const void *ptr)
      53             : {
      54             :     unsigned short s;
      55      523196 :     memcpy(&s, ptr, 2);
      56     1046390 :     return _mm_cvtsi32_si128(s);
      57             : }
      58             : 
      59   215257165 : static inline __m128i GDALCopyInt32ToXMM(const void *ptr)
      60             : {
      61             :     GInt32 i;
      62   215257165 :     memcpy(&i, ptr, 4);
      63   430515340 :     return _mm_cvtsi32_si128(i);
      64             : }
      65             : 
      66         768 : static inline __m128i GDALCopyInt64ToXMM(const void *ptr)
      67             : {
      68             : #if defined(__i386__) || defined(_M_IX86)
      69             :     return _mm_loadl_epi64(static_cast<const __m128i *>(ptr));
      70             : #else
      71             :     GInt64 i;
      72         768 :     memcpy(&i, ptr, 8);
      73        1536 :     return _mm_cvtsi64_si128(i);
      74             : #endif
      75             : }
      76             : 
      77             : static inline void GDALCopyXMMToInt16(const __m128i xmm, void *pDest)
      78             : {
      79             :     GInt16 i = static_cast<GInt16>(_mm_extract_epi16(xmm, 0));
      80             :     memcpy(pDest, &i, 2);
      81             : }
      82             : 
      83             : class XMMReg2Double
      84             : {
      85             :   public:
      86             :     __m128d xmm;
      87             : 
      88             : #if defined(__GNUC__)
      89             : #pragma GCC diagnostic push
      90             : #pragma GCC diagnostic ignored "-Weffc++"
      91             : #endif
      92             :     /* coverity[uninit_member] */
      93             :     XMMReg2Double() = default;
      94             : #if defined(__GNUC__)
      95             : #pragma GCC diagnostic pop
      96             : #endif
      97             : 
      98             :     XMMReg2Double(double val) : xmm(_mm_load_sd(&val))
      99             :     {
     100             :     }
     101             : 
     102     2628270 :     XMMReg2Double(const XMMReg2Double &other) : xmm(other.xmm)
     103             :     {
     104     2628270 :     }
     105             : 
     106     2025280 :     static inline XMMReg2Double Zero()
     107             :     {
     108             :         XMMReg2Double reg;
     109     2025280 :         reg.Zeroize();
     110     2025280 :         return reg;
     111             :     }
     112             : 
     113             :     static inline XMMReg2Double Load1ValHighAndLow(const double *ptr)
     114             :     {
     115             :         XMMReg2Double reg;
     116             :         reg.nsLoad1ValHighAndLow(ptr);
     117             :         return reg;
     118             :     }
     119             : 
     120      142905 :     static inline XMMReg2Double Load2Val(const double *ptr)
     121             :     {
     122             :         XMMReg2Double reg;
     123      142905 :         reg.nsLoad2Val(ptr);
     124      142905 :         return reg;
     125             :     }
     126             : 
     127         768 :     static inline XMMReg2Double Load2Val(const float *ptr)
     128             :     {
     129             :         XMMReg2Double reg;
     130         768 :         reg.nsLoad2Val(ptr);
     131         768 :         return reg;
     132             :     }
     133             : 
     134    25316000 :     static inline XMMReg2Double Load2ValAligned(const double *ptr)
     135             :     {
     136             :         XMMReg2Double reg;
     137    25316000 :         reg.nsLoad2ValAligned(ptr);
     138    25316000 :         return reg;
     139             :     }
     140             : 
     141      523196 :     static inline XMMReg2Double Load2Val(const unsigned char *ptr)
     142             :     {
     143             :         XMMReg2Double reg;
     144      523196 :         reg.nsLoad2Val(ptr);
     145      523196 :         return reg;
     146             :     }
     147             : 
     148       18492 :     static inline XMMReg2Double Load2Val(const short *ptr)
     149             :     {
     150             :         XMMReg2Double reg;
     151       18492 :         reg.nsLoad2Val(ptr);
     152       18492 :         return reg;
     153             :     }
     154             : 
     155       29160 :     static inline XMMReg2Double Load2Val(const unsigned short *ptr)
     156             :     {
     157             :         XMMReg2Double reg;
     158       29160 :         reg.nsLoad2Val(ptr);
     159       29160 :         return reg;
     160             :     }
     161             : 
     162           2 :     static inline XMMReg2Double Equals(const XMMReg2Double &expr1,
     163             :                                        const XMMReg2Double &expr2)
     164             :     {
     165             :         XMMReg2Double reg;
     166           2 :         reg.xmm = _mm_cmpeq_pd(expr1.xmm, expr2.xmm);
     167           2 :         return reg;
     168             :     }
     169             : 
     170     2592772 :     static inline XMMReg2Double NotEquals(const XMMReg2Double &expr1,
     171             :                                           const XMMReg2Double &expr2)
     172             :     {
     173             :         XMMReg2Double reg;
     174     2592772 :         reg.xmm = _mm_cmpneq_pd(expr1.xmm, expr2.xmm);
     175     2627642 :         return reg;
     176             :     }
     177             : 
     178           6 :     static inline XMMReg2Double Greater(const XMMReg2Double &expr1,
     179             :                                         const XMMReg2Double &expr2)
     180             :     {
     181             :         XMMReg2Double reg;
     182           6 :         reg.xmm = _mm_cmpgt_pd(expr1.xmm, expr2.xmm);
     183           6 :         return reg;
     184             :     }
     185             : 
     186     2593090 :     static inline XMMReg2Double And(const XMMReg2Double &expr1,
     187             :                                     const XMMReg2Double &expr2)
     188             :     {
     189             :         XMMReg2Double reg;
     190     2593090 :         reg.xmm = _mm_and_pd(expr1.xmm, expr2.xmm);
     191     2632400 :         return reg;
     192             :     }
     193             : 
     194           2 :     static inline XMMReg2Double Ternary(const XMMReg2Double &cond,
     195             :                                         const XMMReg2Double &true_expr,
     196             :                                         const XMMReg2Double &false_expr)
     197             :     {
     198             :         XMMReg2Double reg;
     199           4 :         reg.xmm = _mm_or_pd(_mm_and_pd(cond.xmm, true_expr.xmm),
     200           2 :                             _mm_andnot_pd(cond.xmm, false_expr.xmm));
     201           2 :         return reg;
     202             :     }
     203             : 
     204     7827272 :     static inline XMMReg2Double Min(const XMMReg2Double &expr1,
     205             :                                     const XMMReg2Double &expr2)
     206             :     {
     207             :         XMMReg2Double reg;
     208     7827272 :         reg.xmm = _mm_min_pd(expr1.xmm, expr2.xmm);
     209     8039692 :         return reg;
     210             :     }
     211             : 
     212    70854601 :     inline void nsLoad1ValHighAndLow(const double *ptr)
     213             :     {
     214    70854601 :         xmm = _mm_load1_pd(ptr);
     215    70854601 :     }
     216             : 
     217   329410017 :     inline void nsLoad2Val(const double *ptr)
     218             :     {
     219   329410017 :         xmm = _mm_loadu_pd(ptr);
     220   329410017 :     }
     221             : 
     222   103359000 :     inline void nsLoad2ValAligned(const double *ptr)
     223             :     {
     224   103359000 :         xmm = _mm_load_pd(ptr);
     225   103359000 :     }
     226             : 
     227         768 :     inline void nsLoad2Val(const float *ptr)
     228             :     {
     229        1536 :         xmm = _mm_cvtps_pd(_mm_castsi128_ps(GDALCopyInt64ToXMM(ptr)));
     230         768 :     }
     231             : 
     232      523196 :     inline void nsLoad2Val(const unsigned char *ptr)
     233             :     {
     234      523196 :         __m128i xmm_i = GDALCopyInt16ToXMM(ptr);
     235             : #ifdef __SSE4_1__
     236             :         xmm_i = _mm_cvtepu8_epi32(xmm_i);
     237             : #else
     238     1046390 :         xmm_i = _mm_unpacklo_epi8(xmm_i, _mm_setzero_si128());
     239     1046390 :         xmm_i = _mm_unpacklo_epi16(xmm_i, _mm_setzero_si128());
     240             : #endif
     241      523196 :         xmm = _mm_cvtepi32_pd(xmm_i);
     242      523196 :     }
     243             : 
     244     2046162 :     inline void nsLoad2Val(const short *ptr)
     245             :     {
     246     2046162 :         __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
     247             : #ifdef __SSE4_1__
     248             :         xmm_i = _mm_cvtepi16_epi32(xmm_i);
     249             : #else
     250     2046162 :         xmm_i = _mm_unpacklo_epi16(
     251             :             xmm_i, xmm_i); /* 0|0|0|0|0|0|b|a --> 0|0|0|0|b|b|a|a */
     252     2046162 :         xmm_i = _mm_srai_epi32(
     253             :             xmm_i, 16); /* 0|0|0|0|b|b|a|a --> 0|0|0|0|sign(b)|b|sign(a)|a */
     254             : #endif
     255     2046162 :         xmm = _mm_cvtepi32_pd(xmm_i);
     256     2046162 :     }
     257             : 
     258    42771602 :     inline void nsLoad2Val(const unsigned short *ptr)
     259             :     {
     260    42771602 :         __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
     261             : #ifdef __SSE4_1__
     262             :         xmm_i = _mm_cvtepu16_epi32(xmm_i);
     263             : #else
     264    85786204 :         xmm_i = _mm_unpacklo_epi16(
     265             :             xmm_i,
     266             :             _mm_setzero_si128()); /* 0|0|0|0|0|0|b|a --> 0|0|0|0|0|b|0|a */
     267             : #endif
     268    43547402 :         xmm = _mm_cvtepi32_pd(xmm_i);
     269    43547402 :     }
     270             : 
     271   170624001 :     static inline void Load4Val(const unsigned char *ptr, XMMReg2Double &low,
     272             :                                 XMMReg2Double &high)
     273             :     {
     274   170624001 :         __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
     275             : #ifdef __SSE4_1__
     276             :         xmm_i = _mm_cvtepu8_epi32(xmm_i);
     277             : #else
     278   342078002 :         xmm_i = _mm_unpacklo_epi8(xmm_i, _mm_setzero_si128());
     279   342268002 :         xmm_i = _mm_unpacklo_epi16(xmm_i, _mm_setzero_si128());
     280             : #endif
     281   170866001 :         low.xmm = _mm_cvtepi32_pd(xmm_i);
     282   171197001 :         high.xmm =
     283   170866001 :             _mm_cvtepi32_pd(_mm_shuffle_epi32(xmm_i, _MM_SHUFFLE(3, 2, 3, 2)));
     284   171197001 :     }
     285             : 
     286             :     static inline void Load4Val(const short *ptr, XMMReg2Double &low,
     287             :                                 XMMReg2Double &high)
     288             :     {
     289             :         low.nsLoad2Val(ptr);
     290             :         high.nsLoad2Val(ptr + 2);
     291             :     }
     292             : 
     293             :     static inline void Load4Val(const unsigned short *ptr, XMMReg2Double &low,
     294             :                                 XMMReg2Double &high)
     295             :     {
     296             :         low.nsLoad2Val(ptr);
     297             :         high.nsLoad2Val(ptr + 2);
     298             :     }
     299             : 
     300             :     static inline void Load4Val(const double *ptr, XMMReg2Double &low,
     301             :                                 XMMReg2Double &high)
     302             :     {
     303             :         low.nsLoad2Val(ptr);
     304             :         high.nsLoad2Val(ptr + 2);
     305             :     }
     306             : 
     307       37633 :     static inline void Load4Val(const float *ptr, XMMReg2Double &low,
     308             :                                 XMMReg2Double &high)
     309             :     {
     310       37633 :         __m128 temp1 = _mm_loadu_ps(ptr);
     311       37633 :         __m128 temp2 = _mm_shuffle_ps(temp1, temp1, _MM_SHUFFLE(3, 2, 3, 2));
     312       37633 :         low.xmm = _mm_cvtps_pd(temp1);
     313       37633 :         high.xmm = _mm_cvtps_pd(temp2);
     314       37633 :     }
     315             : 
     316   283600000 :     inline void Zeroize()
     317             :     {
     318   283600000 :         xmm = _mm_setzero_pd();
     319   283600000 :     }
     320             : 
     321   777839037 :     inline XMMReg2Double &operator=(const XMMReg2Double &other)
     322             :     {
     323   777839037 :         xmm = other.xmm;
     324   777839037 :         return *this;
     325             :     }
     326             : 
     327   596984003 :     inline XMMReg2Double &operator+=(const XMMReg2Double &other)
     328             :     {
     329   596984003 :         xmm = _mm_add_pd(xmm, other.xmm);
     330   596984003 :         return *this;
     331             :     }
     332             : 
     333    13641702 :     inline XMMReg2Double &operator*=(const XMMReg2Double &other)
     334             :     {
     335    13641702 :         xmm = _mm_mul_pd(xmm, other.xmm);
     336    13641702 :         return *this;
     337             :     }
     338             : 
     339   137487009 :     inline XMMReg2Double operator+(const XMMReg2Double &other) const
     340             :     {
     341             :         XMMReg2Double ret;
     342   137487009 :         ret.xmm = _mm_add_pd(xmm, other.xmm);
     343   137487009 :         return ret;
     344             :     }
     345             : 
     346           2 :     inline XMMReg2Double operator-(const XMMReg2Double &other) const
     347             :     {
     348             :         XMMReg2Double ret;
     349           2 :         ret.xmm = _mm_sub_pd(xmm, other.xmm);
     350           2 :         return ret;
     351             :     }
     352             : 
     353   646228002 :     inline XMMReg2Double operator*(const XMMReg2Double &other) const
     354             :     {
     355             :         XMMReg2Double ret;
     356   646228002 :         ret.xmm = _mm_mul_pd(xmm, other.xmm);
     357   646228002 :         return ret;
     358             :     }
     359             : 
     360     2619502 :     inline XMMReg2Double operator/(const XMMReg2Double &other) const
     361             :     {
     362             :         XMMReg2Double ret;
     363     2619502 :         ret.xmm = _mm_div_pd(xmm, other.xmm);
     364     2619502 :         return ret;
     365             :     }
     366             : 
     367   139492001 :     inline double GetHorizSum() const
     368             :     {
     369             :         __m128d xmm2;
     370   139492001 :         xmm2 = _mm_shuffle_pd(
     371             :             xmm, xmm,
     372             :             _MM_SHUFFLE2(0, 1)); /* transfer high word into low word of xmm2 */
     373   420417003 :         return _mm_cvtsd_f64(_mm_add_sd(xmm, xmm2));
     374             :     }
     375             : 
     376          32 :     inline void Store2Val(double *ptr) const
     377             :     {
     378          32 :         _mm_storeu_pd(ptr, xmm);
     379          32 :     }
     380             : 
     381             :     inline void Store2ValAligned(double *ptr) const
     382             :     {
     383             :         _mm_store_pd(ptr, xmm);
     384             :     }
     385             : 
     386    73476002 :     inline void Store2Val(float *ptr) const
     387             :     {
     388   147137004 :         __m128i xmm_i = _mm_castps_si128(_mm_cvtpd_ps(xmm));
     389    73661302 :         GDALCopyXMMToInt64(xmm_i, reinterpret_cast<GInt64 *>(ptr));
     390    73625202 :     }
     391             : 
     392             :     inline void Store2Val(unsigned char *ptr) const
     393             :     {
     394             :         __m128i tmp = _mm_cvttpd_epi32(_mm_add_pd(
     395             :             xmm,
     396             :             _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
     397             :         tmp = _mm_packs_epi32(tmp, tmp);
     398             :         tmp = _mm_packus_epi16(tmp, tmp);
     399             :         GDALCopyXMMToInt16(tmp, reinterpret_cast<GInt16 *>(ptr));
     400             :     }
     401             : 
     402     4606472 :     inline void Store2Val(unsigned short *ptr) const
     403             :     {
     404     4606472 :         __m128i tmp = _mm_cvttpd_epi32(_mm_add_pd(
     405     4606472 :             xmm,
     406             :             _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
     407             :         // X X X X 0 B 0 A --> X X X X A A B A
     408     4671412 :         tmp = _mm_shufflelo_epi16(tmp, 0 | (2 << 2));
     409     4711382 :         GDALCopyXMMToInt32(tmp, reinterpret_cast<GInt32 *>(ptr));
     410     4569252 :     }
     411             : 
     412           8 :     inline void StoreMask(unsigned char *ptr) const
     413             :     {
     414           8 :         _mm_storeu_si128(reinterpret_cast<__m128i *>(ptr),
     415           8 :                          _mm_castpd_si128(xmm));
     416           8 :     }
     417             : 
     418             :     inline operator double() const
     419             :     {
     420             :         return _mm_cvtsd_f64(xmm);
     421             :     }
     422             : };
     423             : 
     424             : #else
     425             : 
     426             : #ifndef NO_WARN_USE_SSE2_EMULATION
     427             : #warning "Software emulation of SSE2 !"
     428             : #endif
     429             : 
     430             : class XMMReg2Double
     431             : {
     432             :   public:
     433             :     double low;
     434             :     double high;
     435             : 
     436          84 :     XMMReg2Double()
     437          84 :     {
     438          84 :     }
     439             : 
     440             :     XMMReg2Double(double val)
     441             :     {
     442             :         low = val;
     443             :         high = 0.0;
     444             :     }
     445             : 
     446             :     XMMReg2Double(const XMMReg2Double &other) : low(other.low), high(other.high)
     447             :     {
     448             :     }
     449             : 
     450             :     static inline XMMReg2Double Zero()
     451             :     {
     452             :         XMMReg2Double reg;
     453             :         reg.Zeroize();
     454             :         return reg;
     455             :     }
     456             : 
     457             :     static inline XMMReg2Double Load1ValHighAndLow(const double *ptr)
     458             :     {
     459             :         XMMReg2Double reg;
     460             :         reg.nsLoad1ValHighAndLow(ptr);
     461             :         return reg;
     462             :     }
     463             : 
     464           2 :     static inline XMMReg2Double Equals(const XMMReg2Double &expr1,
     465             :                                        const XMMReg2Double &expr2)
     466             :     {
     467           2 :         XMMReg2Double reg;
     468             : 
     469           2 :         if (expr1.low == expr2.low)
     470           2 :             memset(&(reg.low), 0xFF, sizeof(double));
     471             :         else
     472           0 :             reg.low = 0;
     473             : 
     474           2 :         if (expr1.high == expr2.high)
     475           2 :             memset(&(reg.high), 0xFF, sizeof(double));
     476             :         else
     477           0 :             reg.high = 0;
     478             : 
     479           2 :         return reg;
     480             :     }
     481             : 
     482           2 :     static inline XMMReg2Double NotEquals(const XMMReg2Double &expr1,
     483             :                                           const XMMReg2Double &expr2)
     484             :     {
     485           2 :         XMMReg2Double reg;
     486             : 
     487           2 :         if (expr1.low != expr2.low)
     488           0 :             memset(&(reg.low), 0xFF, sizeof(double));
     489             :         else
     490           2 :             reg.low = 0;
     491             : 
     492           2 :         if (expr1.high != expr2.high)
     493           0 :             memset(&(reg.high), 0xFF, sizeof(double));
     494             :         else
     495           2 :             reg.high = 0;
     496             : 
     497           2 :         return reg;
     498             :     }
     499             : 
     500           6 :     static inline XMMReg2Double Greater(const XMMReg2Double &expr1,
     501             :                                         const XMMReg2Double &expr2)
     502             :     {
     503           6 :         XMMReg2Double reg;
     504             : 
     505           6 :         if (expr1.low > expr2.low)
     506           2 :             memset(&(reg.low), 0xFF, sizeof(double));
     507             :         else
     508           4 :             reg.low = 0;
     509             : 
     510           6 :         if (expr1.high > expr2.high)
     511           2 :             memset(&(reg.high), 0xFF, sizeof(double));
     512             :         else
     513           4 :             reg.high = 0;
     514             : 
     515           6 :         return reg;
     516             :     }
     517             : 
     518             :     static inline XMMReg2Double And(const XMMReg2Double &expr1,
     519             :                                     const XMMReg2Double &expr2)
     520             :     {
     521             :         XMMReg2Double reg;
     522             :         int low1[2], high1[2];
     523             :         int low2[2], high2[2];
     524             :         memcpy(low1, &expr1.low, sizeof(double));
     525             :         memcpy(high1, &expr1.high, sizeof(double));
     526             :         memcpy(low2, &expr2.low, sizeof(double));
     527             :         memcpy(high2, &expr2.high, sizeof(double));
     528             :         low1[0] &= low2[0];
     529             :         low1[1] &= low2[1];
     530             :         high1[0] &= high2[0];
     531             :         high1[1] &= high2[1];
     532             :         memcpy(&reg.low, low1, sizeof(double));
     533             :         memcpy(&reg.high, high1, sizeof(double));
     534             :         return reg;
     535             :     }
     536             : 
     537           2 :     static inline XMMReg2Double Ternary(const XMMReg2Double &cond,
     538             :                                         const XMMReg2Double &true_expr,
     539             :                                         const XMMReg2Double &false_expr)
     540             :     {
     541           2 :         XMMReg2Double reg;
     542           2 :         if (cond.low != 0)
     543           1 :             reg.low = true_expr.low;
     544             :         else
     545           1 :             reg.low = false_expr.low;
     546           2 :         if (cond.high != 0)
     547           1 :             reg.high = true_expr.high;
     548             :         else
     549           1 :             reg.high = false_expr.high;
     550           2 :         return reg;
     551             :     }
     552             : 
     553           2 :     static inline XMMReg2Double Min(const XMMReg2Double &expr1,
     554             :                                     const XMMReg2Double &expr2)
     555             :     {
     556           2 :         XMMReg2Double reg;
     557           2 :         reg.low = (expr1.low < expr2.low) ? expr1.low : expr2.low;
     558           2 :         reg.high = (expr1.high < expr2.high) ? expr1.high : expr2.high;
     559           2 :         return reg;
     560             :     }
     561             : 
     562           1 :     static inline XMMReg2Double Load2Val(const double *ptr)
     563             :     {
     564           1 :         XMMReg2Double reg;
     565           1 :         reg.nsLoad2Val(ptr);
     566           1 :         return reg;
     567             :     }
     568             : 
     569             :     static inline XMMReg2Double Load2ValAligned(const double *ptr)
     570             :     {
     571             :         XMMReg2Double reg;
     572             :         reg.nsLoad2ValAligned(ptr);
     573             :         return reg;
     574             :     }
     575             : 
     576             :     static inline XMMReg2Double Load2Val(const float *ptr)
     577             :     {
     578             :         XMMReg2Double reg;
     579             :         reg.nsLoad2Val(ptr);
     580             :         return reg;
     581             :     }
     582             : 
     583             :     static inline XMMReg2Double Load2Val(const unsigned char *ptr)
     584             :     {
     585             :         XMMReg2Double reg;
     586             :         reg.nsLoad2Val(ptr);
     587             :         return reg;
     588             :     }
     589             : 
     590             :     static inline XMMReg2Double Load2Val(const short *ptr)
     591             :     {
     592             :         XMMReg2Double reg;
     593             :         reg.nsLoad2Val(ptr);
     594             :         return reg;
     595             :     }
     596             : 
     597             :     static inline XMMReg2Double Load2Val(const unsigned short *ptr)
     598             :     {
     599             :         XMMReg2Double reg;
     600             :         reg.nsLoad2Val(ptr);
     601             :         return reg;
     602             :     }
     603             : 
     604           1 :     inline void nsLoad1ValHighAndLow(const double *ptr)
     605             :     {
     606           1 :         low = ptr[0];
     607           1 :         high = ptr[0];
     608           1 :     }
     609             : 
     610          17 :     inline void nsLoad2Val(const double *ptr)
     611             :     {
     612          17 :         low = ptr[0];
     613          17 :         high = ptr[1];
     614          17 :     }
     615             : 
     616             :     inline void nsLoad2ValAligned(const double *ptr)
     617             :     {
     618             :         low = ptr[0];
     619             :         high = ptr[1];
     620             :     }
     621             : 
     622           2 :     inline void nsLoad2Val(const float *ptr)
     623             :     {
     624           2 :         low = ptr[0];
     625           2 :         high = ptr[1];
     626           2 :     }
     627             : 
     628             :     inline void nsLoad2Val(const unsigned char *ptr)
     629             :     {
     630             :         low = ptr[0];
     631             :         high = ptr[1];
     632             :     }
     633             : 
     634           2 :     inline void nsLoad2Val(const short *ptr)
     635             :     {
     636           2 :         low = ptr[0];
     637           2 :         high = ptr[1];
     638           2 :     }
     639             : 
     640           2 :     inline void nsLoad2Val(const unsigned short *ptr)
     641             :     {
     642           2 :         low = ptr[0];
     643           2 :         high = ptr[1];
     644           2 :     }
     645             : 
     646           1 :     static inline void Load4Val(const unsigned char *ptr, XMMReg2Double &low,
     647             :                                 XMMReg2Double &high)
     648             :     {
     649           1 :         low.low = ptr[0];
     650           1 :         low.high = ptr[1];
     651           1 :         high.low = ptr[2];
     652           1 :         high.high = ptr[3];
     653           1 :     }
     654             : 
     655             :     static inline void Load4Val(const short *ptr, XMMReg2Double &low,
     656             :                                 XMMReg2Double &high)
     657             :     {
     658             :         low.nsLoad2Val(ptr);
     659             :         high.nsLoad2Val(ptr + 2);
     660             :     }
     661             : 
     662             :     static inline void Load4Val(const unsigned short *ptr, XMMReg2Double &low,
     663             :                                 XMMReg2Double &high)
     664             :     {
     665             :         low.nsLoad2Val(ptr);
     666             :         high.nsLoad2Val(ptr + 2);
     667             :     }
     668             : 
     669             :     static inline void Load4Val(const double *ptr, XMMReg2Double &low,
     670             :                                 XMMReg2Double &high)
     671             :     {
     672             :         low.nsLoad2Val(ptr);
     673             :         high.nsLoad2Val(ptr + 2);
     674             :     }
     675             : 
     676           1 :     static inline void Load4Val(const float *ptr, XMMReg2Double &low,
     677             :                                 XMMReg2Double &high)
     678             :     {
     679           1 :         low.nsLoad2Val(ptr);
     680           1 :         high.nsLoad2Val(ptr + 2);
     681           1 :     }
     682             : 
     683             :     inline void Zeroize()
     684             :     {
     685             :         low = 0.0;
     686             :         high = 0.0;
     687             :     }
     688             : 
     689          37 :     inline XMMReg2Double &operator=(const XMMReg2Double &other)
     690             :     {
     691          37 :         low = other.low;
     692          37 :         high = other.high;
     693          37 :         return *this;
     694             :     }
     695             : 
     696           3 :     inline XMMReg2Double &operator+=(const XMMReg2Double &other)
     697             :     {
     698           3 :         low += other.low;
     699           3 :         high += other.high;
     700           3 :         return *this;
     701             :     }
     702             : 
     703           2 :     inline XMMReg2Double &operator*=(const XMMReg2Double &other)
     704             :     {
     705           2 :         low *= other.low;
     706           2 :         high *= other.high;
     707           2 :         return *this;
     708             :     }
     709             : 
     710           9 :     inline XMMReg2Double operator+(const XMMReg2Double &other) const
     711             :     {
     712           9 :         XMMReg2Double ret;
     713           9 :         ret.low = low + other.low;
     714           9 :         ret.high = high + other.high;
     715           9 :         return ret;
     716             :     }
     717             : 
     718           2 :     inline XMMReg2Double operator-(const XMMReg2Double &other) const
     719             :     {
     720           2 :         XMMReg2Double ret;
     721           2 :         ret.low = low - other.low;
     722           2 :         ret.high = high - other.high;
     723           2 :         return ret;
     724             :     }
     725             : 
     726           2 :     inline XMMReg2Double operator*(const XMMReg2Double &other) const
     727             :     {
     728           2 :         XMMReg2Double ret;
     729           2 :         ret.low = low * other.low;
     730           2 :         ret.high = high * other.high;
     731           2 :         return ret;
     732             :     }
     733             : 
     734           2 :     inline XMMReg2Double operator/(const XMMReg2Double &other) const
     735             :     {
     736           2 :         XMMReg2Double ret;
     737           2 :         ret.low = low / other.low;
     738           2 :         ret.high = high / other.high;
     739           2 :         return ret;
     740             :     }
     741             : 
     742           1 :     inline double GetHorizSum() const
     743             :     {
     744           1 :         return low + high;
     745             :     }
     746             : 
     747          32 :     inline void Store2Val(double *ptr) const
     748             :     {
     749          32 :         ptr[0] = low;
     750          32 :         ptr[1] = high;
     751          32 :     }
     752             : 
     753             :     inline void Store2ValAligned(double *ptr) const
     754             :     {
     755             :         ptr[0] = low;
     756             :         ptr[1] = high;
     757             :     }
     758             : 
     759           2 :     inline void Store2Val(float *ptr) const
     760             :     {
     761           2 :         ptr[0] = static_cast<float>(low);
     762           2 :         ptr[1] = static_cast<float>(high);
     763           2 :     }
     764             : 
     765           2 :     void Store2Val(unsigned char *ptr) const
     766             :     {
     767           2 :         ptr[0] = (unsigned char)(low + 0.5);
     768           2 :         ptr[1] = (unsigned char)(high + 0.5);
     769           2 :     }
     770             : 
     771           2 :     void Store2Val(unsigned short *ptr) const
     772             :     {
     773           2 :         ptr[0] = (GUInt16)(low + 0.5);
     774           2 :         ptr[1] = (GUInt16)(high + 0.5);
     775           2 :     }
     776             : 
     777           8 :     inline void StoreMask(unsigned char *ptr) const
     778             :     {
     779           8 :         memcpy(ptr, &low, 8);
     780           8 :         memcpy(ptr + 8, &high, 8);
     781           8 :     }
     782             : 
     783             :     inline operator double() const
     784             :     {
     785             :         return low;
     786             :     }
     787             : };
     788             : 
     789             : #endif /*  defined(__x86_64) || defined(_M_X64) */
     790             : 
     791             : #if defined(__AVX__) && !defined(USE_SSE2_EMULATION)
     792             : 
     793             : #include <immintrin.h>
     794             : 
     795             : class XMMReg4Double
     796             : {
     797             :   public:
     798             :     __m256d ymm;
     799             : 
     800             :     XMMReg4Double() : ymm(_mm256_setzero_pd())
     801             :     {
     802             :     }
     803             : 
     804             :     XMMReg4Double(const XMMReg4Double &other) : ymm(other.ymm)
     805             :     {
     806             :     }
     807             : 
     808             :     static inline XMMReg4Double Zero()
     809             :     {
     810             :         XMMReg4Double reg;
     811             :         reg.Zeroize();
     812             :         return reg;
     813             :     }
     814             : 
     815             :     inline void Zeroize()
     816             :     {
     817             :         ymm = _mm256_setzero_pd();
     818             :     }
     819             : 
     820             :     static inline XMMReg4Double Load1ValHighAndLow(const double *ptr)
     821             :     {
     822             :         XMMReg4Double reg;
     823             :         reg.nsLoad1ValHighAndLow(ptr);
     824             :         return reg;
     825             :     }
     826             : 
     827             :     inline void nsLoad1ValHighAndLow(const double *ptr)
     828             :     {
     829             :         ymm = _mm256_set1_pd(*ptr);
     830             :     }
     831             : 
     832             :     static inline XMMReg4Double Load4Val(const unsigned char *ptr)
     833             :     {
     834             :         XMMReg4Double reg;
     835             :         reg.nsLoad4Val(ptr);
     836             :         return reg;
     837             :     }
     838             : 
     839             :     inline void nsLoad4Val(const unsigned char *ptr)
     840             :     {
     841             :         __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
     842             :         xmm_i = _mm_cvtepu8_epi32(xmm_i);
     843             :         ymm = _mm256_cvtepi32_pd(xmm_i);
     844             :     }
     845             : 
     846             :     static inline XMMReg4Double Load4Val(const short *ptr)
     847             :     {
     848             :         XMMReg4Double reg;
     849             :         reg.nsLoad4Val(ptr);
     850             :         return reg;
     851             :     }
     852             : 
     853             :     inline void nsLoad4Val(const short *ptr)
     854             :     {
     855             :         __m128i xmm_i = GDALCopyInt64ToXMM(ptr);
     856             :         xmm_i = _mm_cvtepi16_epi32(xmm_i);
     857             :         ymm = _mm256_cvtepi32_pd(xmm_i);
     858             :     }
     859             : 
     860             :     static inline XMMReg4Double Load4Val(const unsigned short *ptr)
     861             :     {
     862             :         XMMReg4Double reg;
     863             :         reg.nsLoad4Val(ptr);
     864             :         return reg;
     865             :     }
     866             : 
     867             :     inline void nsLoad4Val(const unsigned short *ptr)
     868             :     {
     869             :         __m128i xmm_i = GDALCopyInt64ToXMM(ptr);
     870             :         xmm_i = _mm_cvtepu16_epi32(xmm_i);
     871             :         ymm = _mm256_cvtepi32_pd(
     872             :             xmm_i);  // ok to use signed conversion since we are in the ushort
     873             :                      // range, so cannot be interpreted as negative int32
     874             :     }
     875             : 
     876             :     static inline XMMReg4Double Load4Val(const double *ptr)
     877             :     {
     878             :         XMMReg4Double reg;
     879             :         reg.nsLoad4Val(ptr);
     880             :         return reg;
     881             :     }
     882             : 
     883             :     inline void nsLoad4Val(const double *ptr)
     884             :     {
     885             :         ymm = _mm256_loadu_pd(ptr);
     886             :     }
     887             : 
     888             :     static inline XMMReg4Double Load4ValAligned(const double *ptr)
     889             :     {
     890             :         XMMReg4Double reg;
     891             :         reg.nsLoad4ValAligned(ptr);
     892             :         return reg;
     893             :     }
     894             : 
     895             :     inline void nsLoad4ValAligned(const double *ptr)
     896             :     {
     897             :         ymm = _mm256_load_pd(ptr);
     898             :     }
     899             : 
     900             :     static inline XMMReg4Double Load4Val(const float *ptr)
     901             :     {
     902             :         XMMReg4Double reg;
     903             :         reg.nsLoad4Val(ptr);
     904             :         return reg;
     905             :     }
     906             : 
     907             :     inline void nsLoad4Val(const float *ptr)
     908             :     {
     909             :         ymm = _mm256_cvtps_pd(_mm_loadu_ps(ptr));
     910             :     }
     911             : 
     912             :     static inline XMMReg4Double Equals(const XMMReg4Double &expr1,
     913             :                                        const XMMReg4Double &expr2)
     914             :     {
     915             :         XMMReg4Double reg;
     916             :         reg.ymm = _mm256_cmp_pd(expr1.ymm, expr2.ymm, _CMP_EQ_OQ);
     917             :         return reg;
     918             :     }
     919             : 
     920             :     static inline XMMReg4Double NotEquals(const XMMReg4Double &expr1,
     921             :                                           const XMMReg4Double &expr2)
     922             :     {
     923             :         XMMReg4Double reg;
     924             :         reg.ymm = _mm256_cmp_pd(expr1.ymm, expr2.ymm, _CMP_NEQ_OQ);
     925             :         return reg;
     926             :     }
     927             : 
     928             :     static inline XMMReg4Double Greater(const XMMReg4Double &expr1,
     929             :                                         const XMMReg4Double &expr2)
     930             :     {
     931             :         XMMReg4Double reg;
     932             :         reg.ymm = _mm256_cmp_pd(expr1.ymm, expr2.ymm, _CMP_GT_OQ);
     933             :         return reg;
     934             :     }
     935             : 
     936             :     static inline XMMReg4Double And(const XMMReg4Double &expr1,
     937             :                                     const XMMReg4Double &expr2)
     938             :     {
     939             :         XMMReg4Double reg;
     940             :         reg.ymm = _mm256_and_pd(expr1.ymm, expr2.ymm);
     941             :         return reg;
     942             :     }
     943             : 
     944             :     static inline XMMReg4Double Ternary(const XMMReg4Double &cond,
     945             :                                         const XMMReg4Double &true_expr,
     946             :                                         const XMMReg4Double &false_expr)
     947             :     {
     948             :         XMMReg4Double reg;
     949             :         reg.ymm = _mm256_or_pd(_mm256_and_pd(cond.ymm, true_expr.ymm),
     950             :                                _mm256_andnot_pd(cond.ymm, false_expr.ymm));
     951             :         return reg;
     952             :     }
     953             : 
     954             :     static inline XMMReg4Double Min(const XMMReg4Double &expr1,
     955             :                                     const XMMReg4Double &expr2)
     956             :     {
     957             :         XMMReg4Double reg;
     958             :         reg.ymm = _mm256_min_pd(expr1.ymm, expr2.ymm);
     959             :         return reg;
     960             :     }
     961             : 
     962             :     inline XMMReg4Double &operator=(const XMMReg4Double &other)
     963             :     {
     964             :         ymm = other.ymm;
     965             :         return *this;
     966             :     }
     967             : 
     968             :     inline XMMReg4Double &operator+=(const XMMReg4Double &other)
     969             :     {
     970             :         ymm = _mm256_add_pd(ymm, other.ymm);
     971             :         return *this;
     972             :     }
     973             : 
     974             :     inline XMMReg4Double &operator*=(const XMMReg4Double &other)
     975             :     {
     976             :         ymm = _mm256_mul_pd(ymm, other.ymm);
     977             :         return *this;
     978             :     }
     979             : 
     980             :     inline XMMReg4Double operator+(const XMMReg4Double &other) const
     981             :     {
     982             :         XMMReg4Double ret;
     983             :         ret.ymm = _mm256_add_pd(ymm, other.ymm);
     984             :         return ret;
     985             :     }
     986             : 
     987             :     inline XMMReg4Double operator-(const XMMReg4Double &other) const
     988             :     {
     989             :         XMMReg4Double ret;
     990             :         ret.ymm = _mm256_sub_pd(ymm, other.ymm);
     991             :         return ret;
     992             :     }
     993             : 
     994             :     inline XMMReg4Double operator*(const XMMReg4Double &other) const
     995             :     {
     996             :         XMMReg4Double ret;
     997             :         ret.ymm = _mm256_mul_pd(ymm, other.ymm);
     998             :         return ret;
     999             :     }
    1000             : 
    1001             :     inline XMMReg4Double operator/(const XMMReg4Double &other) const
    1002             :     {
    1003             :         XMMReg4Double ret;
    1004             :         ret.ymm = _mm256_div_pd(ymm, other.ymm);
    1005             :         return ret;
    1006             :     }
    1007             : 
    1008             :     void AddToLow(const XMMReg2Double &other)
    1009             :     {
    1010             :         __m256d ymm2 = _mm256_setzero_pd();
    1011             :         ymm2 = _mm256_insertf128_pd(ymm2, other.xmm, 0);
    1012             :         ymm = _mm256_add_pd(ymm, ymm2);
    1013             :     }
    1014             : 
    1015             :     inline double GetHorizSum() const
    1016             :     {
    1017             :         __m256d ymm_tmp1, ymm_tmp2;
    1018             :         ymm_tmp2 = _mm256_hadd_pd(ymm, ymm);
    1019             :         ymm_tmp1 = _mm256_permute2f128_pd(ymm_tmp2, ymm_tmp2, 1);
    1020             :         ymm_tmp1 = _mm256_add_pd(ymm_tmp1, ymm_tmp2);
    1021             :         return _mm_cvtsd_f64(_mm256_castpd256_pd128(ymm_tmp1));
    1022             :     }
    1023             : 
    1024             :     inline void Store4Val(unsigned char *ptr) const
    1025             :     {
    1026             :         __m128i xmm_i =
    1027             :             _mm256_cvttpd_epi32(_mm256_add_pd(ymm, _mm256_set1_pd(0.5)));
    1028             :         // xmm_i = _mm_packs_epi32(xmm_i, xmm_i);   // Pack int32 to int16
    1029             :         // xmm_i = _mm_packus_epi16(xmm_i, xmm_i);  // Pack int16 to uint8
    1030             :         xmm_i =
    1031             :             _mm_shuffle_epi8(xmm_i, _mm_cvtsi32_si128(0 | (4 << 8) | (8 << 16) |
    1032             :                                                       (12 << 24)));  //  SSSE3
    1033             :         GDALCopyXMMToInt32(xmm_i, reinterpret_cast<GInt32 *>(ptr));
    1034             :     }
    1035             : 
    1036             :     inline void Store4Val(unsigned short *ptr) const
    1037             :     {
    1038             :         __m128i xmm_i =
    1039             :             _mm256_cvttpd_epi32(_mm256_add_pd(ymm, _mm256_set1_pd(0.5)));
    1040             :         xmm_i = _mm_packus_epi32(xmm_i, xmm_i);  // Pack uint32 to uint16
    1041             :         GDALCopyXMMToInt64(xmm_i, reinterpret_cast<GInt64 *>(ptr));
    1042             :     }
    1043             : 
    1044             :     inline void Store4Val(float *ptr) const
    1045             :     {
    1046             :         _mm_storeu_ps(ptr, _mm256_cvtpd_ps(ymm));
    1047             :     }
    1048             : 
    1049             :     inline void Store4Val(double *ptr) const
    1050             :     {
    1051             :         _mm256_storeu_pd(ptr, ymm);
    1052             :     }
    1053             : 
    1054             :     inline void StoreMask(unsigned char *ptr) const
    1055             :     {
    1056             :         _mm256_storeu_si256(reinterpret_cast<__m256i *>(ptr),
    1057             :                             _mm256_castpd_si256(ymm));
    1058             :     }
    1059             : };
    1060             : 
    1061             : #else
    1062             : 
    1063             : class XMMReg4Double
    1064             : {
    1065             :   public:
    1066             :     XMMReg2Double low, high;
    1067             : 
    1068             : #if defined(__GNUC__)
    1069             : #pragma GCC diagnostic push
    1070             : #pragma GCC diagnostic ignored "-Weffc++"
    1071             : #endif
    1072             :     /* coverity[uninit_member] */
    1073          27 :     XMMReg4Double() = default;
    1074             : #if defined(__GNUC__)
    1075             : #pragma GCC diagnostic pop
    1076             : #endif
    1077             : 
    1078     1321010 :     XMMReg4Double(const XMMReg4Double &other) : low(other.low), high(other.high)
    1079             :     {
    1080     1324790 :     }
    1081             : 
    1082   141449000 :     static inline XMMReg4Double Zero()
    1083             :     {
    1084             :         XMMReg4Double reg;
    1085   141449000 :         reg.low.Zeroize();
    1086   141625000 :         reg.high.Zeroize();
    1087   141147000 :         return reg;
    1088             :     }
    1089             : 
    1090    70735402 :     static inline XMMReg4Double Load1ValHighAndLow(const double *ptr)
    1091             :     {
    1092           1 :         XMMReg4Double reg;
    1093    70735402 :         reg.low.nsLoad1ValHighAndLow(ptr);
    1094    71027602 :         reg.high = reg.low;
    1095    70811002 :         return reg;
    1096             :     }
    1097             : 
    1098   170480002 :     static inline XMMReg4Double Load4Val(const unsigned char *ptr)
    1099             :     {
    1100           1 :         XMMReg4Double reg;
    1101   170480002 :         XMMReg2Double::Load4Val(ptr, reg.low, reg.high);
    1102   170820002 :         return reg;
    1103             :     }
    1104             : 
    1105     1013842 :     static inline XMMReg4Double Load4Val(const short *ptr)
    1106             :     {
    1107           1 :         XMMReg4Double reg;
    1108     1013842 :         reg.low.nsLoad2Val(ptr);
    1109     1013842 :         reg.high.nsLoad2Val(ptr + 2);
    1110     1013842 :         return reg;
    1111             :     }
    1112             : 
    1113    21901002 :     static inline XMMReg4Double Load4Val(const unsigned short *ptr)
    1114             :     {
    1115           1 :         XMMReg4Double reg;
    1116    21901002 :         reg.low.nsLoad2Val(ptr);
    1117    22083602 :         reg.high.nsLoad2Val(ptr + 2);
    1118    22020502 :         return reg;
    1119             :     }
    1120             : 
    1121   165723016 :     static inline XMMReg4Double Load4Val(const double *ptr)
    1122             :     {
    1123           8 :         XMMReg4Double reg;
    1124   165723016 :         reg.low.nsLoad2Val(ptr);
    1125   166229016 :         reg.high.nsLoad2Val(ptr + 2);
    1126   167516016 :         return reg;
    1127             :     }
    1128             : 
    1129    39158700 :     static inline XMMReg4Double Load4ValAligned(const double *ptr)
    1130             :     {
    1131             :         XMMReg4Double reg;
    1132    39158700 :         reg.low.nsLoad2ValAligned(ptr);
    1133    39053500 :         reg.high.nsLoad2ValAligned(ptr + 2);
    1134    39057200 :         return reg;
    1135             :     }
    1136             : 
    1137       37634 :     static inline XMMReg4Double Load4Val(const float *ptr)
    1138             :     {
    1139           1 :         XMMReg4Double reg;
    1140       37634 :         XMMReg2Double::Load4Val(ptr, reg.low, reg.high);
    1141       37634 :         return reg;
    1142             :     }
    1143             : 
    1144           2 :     static inline XMMReg4Double Equals(const XMMReg4Double &expr1,
    1145             :                                        const XMMReg4Double &expr2)
    1146             :     {
    1147           1 :         XMMReg4Double reg;
    1148           2 :         reg.low = XMMReg2Double::Equals(expr1.low, expr2.low);
    1149           2 :         reg.high = XMMReg2Double::Equals(expr1.high, expr2.high);
    1150           2 :         return reg;
    1151             :     }
    1152             : 
    1153     1322202 :     static inline XMMReg4Double NotEquals(const XMMReg4Double &expr1,
    1154             :                                           const XMMReg4Double &expr2)
    1155             :     {
    1156           1 :         XMMReg4Double reg;
    1157     1322202 :         reg.low = XMMReg2Double::NotEquals(expr1.low, expr2.low);
    1158     1318432 :         reg.high = XMMReg2Double::NotEquals(expr1.high, expr2.high);
    1159     1321362 :         return reg;
    1160             :     }
    1161             : 
    1162           6 :     static inline XMMReg4Double Greater(const XMMReg4Double &expr1,
    1163             :                                         const XMMReg4Double &expr2)
    1164             :     {
    1165           3 :         XMMReg4Double reg;
    1166           6 :         reg.low = XMMReg2Double::Greater(expr1.low, expr2.low);
    1167           6 :         reg.high = XMMReg2Double::Greater(expr1.high, expr2.high);
    1168           6 :         return reg;
    1169             :     }
    1170             : 
    1171     1320280 :     static inline XMMReg4Double And(const XMMReg4Double &expr1,
    1172             :                                     const XMMReg4Double &expr2)
    1173             :     {
    1174             :         XMMReg4Double reg;
    1175     1320280 :         reg.low = XMMReg2Double::And(expr1.low, expr2.low);
    1176     1323120 :         reg.high = XMMReg2Double::And(expr1.high, expr2.high);
    1177     1323110 :         return reg;
    1178             :     }
    1179             : 
    1180           2 :     static inline XMMReg4Double Ternary(const XMMReg4Double &cond,
    1181             :                                         const XMMReg4Double &true_expr,
    1182             :                                         const XMMReg4Double &false_expr)
    1183             :     {
    1184           1 :         XMMReg4Double reg;
    1185             :         reg.low =
    1186           2 :             XMMReg2Double::Ternary(cond.low, true_expr.low, false_expr.low);
    1187             :         reg.high =
    1188           2 :             XMMReg2Double::Ternary(cond.high, true_expr.high, false_expr.high);
    1189           2 :         return reg;
    1190             :     }
    1191             : 
    1192     4010572 :     static inline XMMReg4Double Min(const XMMReg4Double &expr1,
    1193             :                                     const XMMReg4Double &expr2)
    1194             :     {
    1195           1 :         XMMReg4Double reg;
    1196     4010572 :         reg.low = XMMReg2Double::Min(expr1.low, expr2.low);
    1197     4077302 :         reg.high = XMMReg2Double::Min(expr1.high, expr2.high);
    1198     4076762 :         return reg;
    1199             :     }
    1200             : 
    1201    44358108 :     inline XMMReg4Double &operator=(const XMMReg4Double &other)
    1202             :     {
    1203    44358108 :         low = other.low;
    1204    44344608 :         high = other.high;
    1205    44408708 :         return *this;
    1206             :     }
    1207             : 
    1208   293910002 :     inline XMMReg4Double &operator+=(const XMMReg4Double &other)
    1209             :     {
    1210   293910002 :         low += other.low;
    1211   293599002 :         high += other.high;
    1212   296078002 :         return *this;
    1213             :     }
    1214             : 
    1215     6820852 :     inline XMMReg4Double &operator*=(const XMMReg4Double &other)
    1216             :     {
    1217     6820852 :         low *= other.low;
    1218     6820852 :         high *= other.high;
    1219     6820852 :         return *this;
    1220             :     }
    1221             : 
    1222           8 :     inline XMMReg4Double operator+(const XMMReg4Double &other) const
    1223             :     {
    1224           4 :         XMMReg4Double ret;
    1225           8 :         ret.low = low + other.low;
    1226           8 :         ret.high = high + other.high;
    1227           8 :         return ret;
    1228             :     }
    1229             : 
    1230           2 :     inline XMMReg4Double operator-(const XMMReg4Double &other) const
    1231             :     {
    1232           1 :         XMMReg4Double ret;
    1233           2 :         ret.low = low - other.low;
    1234           2 :         ret.high = high - other.high;
    1235           2 :         return ret;
    1236             :     }
    1237             : 
    1238   322527002 :     inline XMMReg4Double operator*(const XMMReg4Double &other) const
    1239             :     {
    1240           1 :         XMMReg4Double ret;
    1241   322527002 :         ret.low = low * other.low;
    1242   319558002 :         ret.high = high * other.high;
    1243   319003002 :         return ret;
    1244             :     }
    1245             : 
    1246     1324902 :     inline XMMReg4Double operator/(const XMMReg4Double &other) const
    1247             :     {
    1248           1 :         XMMReg4Double ret;
    1249     1324902 :         ret.low = low / other.low;
    1250     1321232 :         ret.high = high / other.high;
    1251     1325142 :         return ret;
    1252             :     }
    1253             : 
    1254      571618 :     void AddToLow(const XMMReg2Double &other)
    1255             :     {
    1256      571618 :         low += other;
    1257      571618 :     }
    1258             : 
    1259   137784002 :     inline double GetHorizSum() const
    1260             :     {
    1261   137784002 :         return (low + high).GetHorizSum();
    1262             :     }
    1263             : 
    1264     1649212 :     inline void Store4Val(unsigned char *ptr) const
    1265             :     {
    1266             : #ifdef USE_SSE2_EMULATION
    1267           1 :         low.Store2Val(ptr);
    1268           1 :         high.Store2Val(ptr + 2);
    1269             : #else
    1270     3303792 :         __m128i tmpLow = _mm_cvttpd_epi32(_mm_add_pd(
    1271     1649211 :             low.xmm,
    1272             :             _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
    1273     3311882 :         __m128i tmpHigh = _mm_cvttpd_epi32(_mm_add_pd(
    1274     1654581 :             high.xmm,
    1275             :             _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
    1276     4970543 :         auto tmp = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(tmpLow),
    1277             :                                                    _mm_castsi128_ps(tmpHigh),
    1278             :                                                    _MM_SHUFFLE(1, 0, 1, 0)));
    1279     1658091 :         tmp = _mm_packs_epi32(tmp, tmp);
    1280     1658841 :         tmp = _mm_packus_epi16(tmp, tmp);
    1281     1658841 :         GDALCopyXMMToInt32(tmp, reinterpret_cast<GInt32 *>(ptr));
    1282             : #endif
    1283     1651812 :     }
    1284             : 
    1285     2444982 :     inline void Store4Val(unsigned short *ptr) const
    1286             :     {
    1287             : #if 1
    1288     2444982 :         low.Store2Val(ptr);
    1289     2436922 :         high.Store2Val(ptr + 2);
    1290             : #else
    1291             :         __m128i xmm0 = _mm_cvtpd_epi32(low.xmm);
    1292             :         __m128i xmm1 = _mm_cvtpd_epi32(high.xmm);
    1293             :         xmm0 = _mm_or_si128(xmm0, _mm_slli_si128(xmm1, 8));
    1294             : #if __SSE4_1__
    1295             :         xmm0 = _mm_packus_epi32(xmm0, xmm0);  // Pack uint32 to uint16
    1296             : #else
    1297             :         xmm0 = _mm_add_epi32(xmm0, _mm_set1_epi32(-32768));
    1298             :         xmm0 = _mm_packs_epi32(xmm0, xmm0);
    1299             :         xmm0 = _mm_sub_epi16(xmm0, _mm_set1_epi16(-32768));
    1300             : #endif
    1301             :         GDALCopyXMMToInt64(xmm0, (GInt64 *)ptr);
    1302             : #endif
    1303     2443002 :     }
    1304             : 
    1305    36914102 :     inline void Store4Val(float *ptr) const
    1306             :     {
    1307    36914102 :         low.Store2Val(ptr);
    1308    37011602 :         high.Store2Val(ptr + 2);
    1309    36955702 :     }
    1310             : 
    1311          32 :     inline void Store4Val(double *ptr) const
    1312             :     {
    1313          32 :         low.Store2Val(ptr);
    1314          32 :         high.Store2Val(ptr + 2);
    1315          32 :     }
    1316             : 
    1317           8 :     inline void StoreMask(unsigned char *ptr) const
    1318             :     {
    1319           8 :         low.StoreMask(ptr);
    1320           8 :         high.StoreMask(ptr + 16);
    1321           8 :     }
    1322             : };
    1323             : 
    1324             : #endif
    1325             : 
    1326             : #endif /* #ifndef DOXYGEN_SKIP */
    1327             : 
    1328             : #endif /* GDALSSE_PRIV_H_INCLUDED */

Generated by: LCOV version 1.14