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

Generated by: LCOV version 1.14