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: 2025-01-18 12:42:00 Functions: 71 71 100.0 %

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

Generated by: LCOV version 1.14