LCOV - code coverage report
Current view: top level - gcore - gdal_avx2_emulation.hpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 58 58 100.0 %
Date: 2026-01-28 12:11:25 Functions: 25 25 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  GDAL
       3             :  * Purpose:  AVX2 emulation with SSE2 + a few SSE4.1 emulation
       4             :  * Author:   Even Rouault <even dot rouault at spatialys dot com>
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2016, Even Rouault <even dot rouault at spatialys dot com>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #ifndef GDAL_AVX2_EMULATION_H_INCLUDED
      13             : #define GDAL_AVX2_EMULATION_H_INCLUDED
      14             : 
      15             : #if defined(USE_NEON_OPTIMIZATIONS)
      16             : #include "include_sse2neon.h"
      17             : #else
      18             : #include <emmintrin.h>
      19             : 
      20             : #ifdef __SSE4_1__
      21             : #include <smmintrin.h>
      22             : #endif
      23             : 
      24             : #endif
      25             : 
      26             : #if defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
      27             : #define GDALmm_min_epu16 _mm_min_epu16
      28             : #define GDALmm_max_epu16 _mm_max_epu16
      29             : #define GDALmm_mullo_epi32 _mm_mullo_epi32
      30             : #define GDALmm_cvtepu8_epi16 _mm_cvtepu8_epi16
      31             : #define GDALmm_cvtepu16_epi32 _mm_cvtepu16_epi32
      32             : #define GDALmm_cvtepu16_epi64 _mm_cvtepu16_epi64
      33             : #define GDALmm_cvtepu32_epi64 _mm_cvtepu32_epi64
      34             : 
      35             : #else
      36             : // Emulation of SSE4.1 _mm_min_epu16 and _mm_max_epu16 with SSE2 only
      37             : 
      38             : static inline __m128i GDALAVX2Emul_mm_cmple_epu16(__m128i x, __m128i y)
      39             : {
      40             :     return _mm_cmpeq_epi16(_mm_subs_epu16(x, y), _mm_setzero_si128());
      41             : }
      42             : 
      43             : static inline __m128i GDALAVX2Emul_mm_ternary(__m128i mask, __m128i then_reg,
      44             :                                               __m128i else_reg)
      45             : {
      46             :     return _mm_or_si128(_mm_and_si128(mask, then_reg),
      47             :                         _mm_andnot_si128(mask, else_reg));
      48             : }
      49             : 
      50             : static inline __m128i GDALmm_min_epu16(__m128i x, __m128i y)
      51             : {
      52             :     const __m128i mask = GDALAVX2Emul_mm_cmple_epu16(x, y);
      53             :     return GDALAVX2Emul_mm_ternary(mask, x, y);
      54             : }
      55             : 
      56             : static inline __m128i GDALmm_max_epu16(__m128i x, __m128i y)
      57             : {
      58             :     const __m128i mask = GDALAVX2Emul_mm_cmple_epu16(x, y);
      59             :     return GDALAVX2Emul_mm_ternary(mask, y, x);
      60             : }
      61             : 
      62             : static inline __m128i GDALmm_mullo_epi32(__m128i x, __m128i y)
      63             : {
      64             :     const __m128i mul02 = _mm_shuffle_epi32(_mm_mul_epu32(x, y), 2 << 2);
      65             :     const __m128i mul13 = _mm_shuffle_epi32(
      66             :         _mm_mul_epu32(_mm_srli_si128(x, 4), _mm_srli_si128(y, 4)), 2 << 2);
      67             :     return _mm_unpacklo_epi32(mul02, mul13);
      68             :     ;
      69             : }
      70             : 
      71             : static inline __m128i GDALmm_cvtepu8_epi16(__m128i x)
      72             : {
      73             :     return _mm_unpacklo_epi8(x, _mm_setzero_si128());
      74             : }
      75             : 
      76             : static inline __m128i GDALmm_cvtepu16_epi32(__m128i x)
      77             : {
      78             :     return _mm_unpacklo_epi16(x, _mm_setzero_si128());
      79             : }
      80             : 
      81             : static inline __m128i GDALmm_cvtepu16_epi64(__m128i x)
      82             : {
      83             :     return _mm_unpacklo_epi32(_mm_unpacklo_epi16(x, _mm_setzero_si128()),
      84             :                               _mm_setzero_si128());
      85             : }
      86             : 
      87             : static inline __m128i GDALmm_cvtepu32_epi64(__m128i x)
      88             : {
      89             :     return _mm_unpacklo_epi32(x, _mm_setzero_si128());
      90             : }
      91             : 
      92             : #endif  // defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
      93             : 
      94             : #ifdef __AVX2__
      95             : 
      96             : #include <immintrin.h>
      97             : 
      98             : typedef __m256i GDALm256i;
      99             : 
     100             : #define GDALmm256_set1_epi8 _mm256_set1_epi8
     101             : #define GDALmm256_set1_epi16 _mm256_set1_epi16
     102             : #define GDALmm256_set1_epi32 _mm256_set1_epi32
     103             : #define GDALmm256_setzero_si256 _mm256_setzero_si256
     104             : #define GDALmm256_load_si256 _mm256_load_si256
     105             : #define GDALmm256_store_si256 _mm256_store_si256
     106             : #define GDALmm256_storeu_si256 _mm256_storeu_si256
     107             : #define GDALmm256_cmpeq_epi8 _mm256_cmpeq_epi8
     108             : #define GDALmm256_sad_epu8 _mm256_sad_epu8
     109             : #define GDALmm256_add_epi32 _mm256_add_epi32
     110             : #define GDALmm256_andnot_si256 _mm256_andnot_si256
     111             : #define GDALmm256_and_si256 _mm256_and_si256
     112             : #define GDALmm256_or_si256 _mm256_or_si256
     113             : #define GDALmm256_min_epu8 _mm256_min_epu8
     114             : #define GDALmm256_max_epu8 _mm256_max_epu8
     115             : #define GDALmm256_extracti128_si256 _mm256_extracti128_si256
     116             : #define GDALmm256_cvtepu8_epi16 _mm256_cvtepu8_epi16
     117             : #define GDALmm256_madd_epi16 _mm256_madd_epi16
     118             : #define GDALmm256_min_epu16 _mm256_min_epu16
     119             : #define GDALmm256_max_epu16 _mm256_max_epu16
     120             : #define GDALmm256_cvtepu16_epi32 _mm256_cvtepu16_epi32
     121             : #define GDALmm256_cvtepu16_epi64 _mm256_cvtepu16_epi64
     122             : #define GDALmm256_cvtepu32_epi64 _mm256_cvtepu32_epi64
     123             : #define GDALmm256_mullo_epi32 _mm256_mullo_epi32
     124             : #define GDALmm256_add_epi64 _mm256_add_epi64
     125             : #define GDALmm256_add_epi16 _mm256_add_epi16
     126             : #define GDALmm256_sub_epi16 _mm256_sub_epi16
     127             : #define GDALmm256_min_epi16 _mm256_min_epi16
     128             : #define GDALmm256_max_epi16 _mm256_max_epi16
     129             : #define GDALmm256_srli_epi16 _mm256_srli_epi16
     130             : #define GDALmm256_srli_epi32 _mm256_srli_epi32
     131             : #define GDALmm256_srli_epi64 _mm256_srli_epi64
     132             : #define GDALmm256_set1_epi64x _mm256_set1_epi64x
     133             : 
     134             : #else
     135             : 
     136             : typedef struct
     137             : {
     138             :     __m128i low;
     139             :     __m128i high;
     140             : } GDALm256i;
     141             : 
     142        2984 : static inline GDALm256i GDALmm256_set1_epi8(char c)
     143             : {
     144             :     GDALm256i reg;
     145        2984 :     reg.low = _mm_set1_epi8(c);
     146        2984 :     reg.high = _mm_set1_epi8(c);
     147        2984 :     return reg;
     148             : }
     149             : 
     150       24682 : static inline GDALm256i GDALmm256_set1_epi16(short s)
     151             : {
     152             :     GDALm256i reg;
     153       24682 :     reg.low = _mm_set1_epi16(s);
     154       24682 :     reg.high = _mm_set1_epi16(s);
     155       24682 :     return reg;
     156             : }
     157             : 
     158        1844 : static inline GDALm256i GDALmm256_set1_epi32(int i)
     159             : {
     160             :     GDALm256i reg;
     161        1844 :     reg.low = _mm_set1_epi32(i);
     162        1844 :     reg.high = _mm_set1_epi32(i);
     163        1844 :     return reg;
     164             : }
     165             : 
     166        1844 : static inline GDALm256i GDALmm256_set1_epi64x(long long i)
     167             : {
     168             :     GDALm256i reg;
     169        1844 :     reg.low = _mm_set1_epi64x(i);
     170        1844 :     reg.high = _mm_set1_epi64x(i);
     171        1844 :     return reg;
     172             : }
     173             : 
     174      573343 : static inline GDALm256i GDALmm256_setzero_si256()
     175             : {
     176             :     GDALm256i reg;
     177      573343 :     reg.low = _mm_setzero_si128();
     178      573343 :     reg.high = _mm_setzero_si128();
     179      573343 :     return reg;
     180             : }
     181             : 
     182     1799450 : static inline GDALm256i GDALmm256_load_si256(GDALm256i const *p)
     183             : {
     184             :     GDALm256i reg;
     185     1799450 :     reg.low = _mm_load_si128(reinterpret_cast<__m128i const *>(p));
     186     1799450 :     reg.high = _mm_load_si128(reinterpret_cast<__m128i const *>(
     187             :         reinterpret_cast<const char *>(p) + 16));
     188     1799450 :     return reg;
     189             : }
     190             : 
     191       50555 : static inline void GDALmm256_store_si256(GDALm256i *p, GDALm256i reg)
     192             : {
     193       50555 :     _mm_store_si128(reinterpret_cast<__m128i *>(p), reg.low);
     194       50555 :     _mm_store_si128(
     195             :         reinterpret_cast<__m128i *>(reinterpret_cast<char *>(p) + 16),
     196             :         reg.high);
     197       50555 : }
     198             : 
     199        4664 : static inline void GDALmm256_storeu_si256(GDALm256i *p, GDALm256i reg)
     200             : {
     201        4664 :     _mm_storeu_si128(reinterpret_cast<__m128i *>(p), reg.low);
     202        4664 :     _mm_storeu_si128(
     203             :         reinterpret_cast<__m128i *>(reinterpret_cast<char *>(p) + 16),
     204             :         reg.high);
     205        4664 : }
     206             : 
     207             : #define DEFINE_BINARY_MM256(mm256name, mm128name)                              \
     208             :     static inline GDALm256i mm256name(GDALm256i r1, GDALm256i r2)              \
     209             :     {                                                                          \
     210             :         GDALm256i reg;                                                         \
     211             :         reg.low = mm128name(r1.low, r2.low);                                   \
     212             :         reg.high = mm128name(r1.high, r2.high);                                \
     213             :         return reg;                                                            \
     214             :     }
     215             : 
     216       52470 : DEFINE_BINARY_MM256(GDALmm256_cmpeq_epi8, _mm_cmpeq_epi8)
     217     1567390 : DEFINE_BINARY_MM256(GDALmm256_sad_epu8, _mm_sad_epu8)
     218     5777150 : DEFINE_BINARY_MM256(GDALmm256_add_epi32, _mm_add_epi32)
     219       52470 : DEFINE_BINARY_MM256(GDALmm256_andnot_si256, _mm_andnot_si128)
     220     2695980 : DEFINE_BINARY_MM256(GDALmm256_and_si256, _mm_and_si128)
     221       26160 : DEFINE_BINARY_MM256(GDALmm256_or_si256, _mm_or_si128)
     222      756150 : DEFINE_BINARY_MM256(GDALmm256_min_epu8, _mm_min_epu8)
     223     1862580 : DEFINE_BINARY_MM256(GDALmm256_max_epu8, _mm_max_epu8)
     224     3644830 : DEFINE_BINARY_MM256(GDALmm256_madd_epi16, _mm_madd_epi16)
     225             : DEFINE_BINARY_MM256(GDALmm256_min_epu16, GDALmm_min_epu16)
     226             : DEFINE_BINARY_MM256(GDALmm256_max_epu16, GDALmm_max_epu16)
     227             : DEFINE_BINARY_MM256(GDALmm256_mullo_epi32, GDALmm_mullo_epi32)
     228     1129870 : DEFINE_BINARY_MM256(GDALmm256_add_epi64, _mm_add_epi64)
     229     3171520 : DEFINE_BINARY_MM256(GDALmm256_add_epi16, _mm_add_epi16)
     230       10572 : DEFINE_BINARY_MM256(GDALmm256_sub_epi16, _mm_sub_epi16)
     231     3111880 : DEFINE_BINARY_MM256(GDALmm256_min_epi16, _mm_min_epi16)
     232     3111880 : DEFINE_BINARY_MM256(GDALmm256_max_epi16, _mm_max_epi16)
     233             : 
     234             : static inline __m128i GDALmm256_extracti128_si256(GDALm256i reg, int index)
     235             : {
     236             :     return (index == 0) ? reg.low : reg.high;
     237             : }
     238             : 
     239             : #define DEFINE_CVTE_MM256(mm256name, mm128name)                                \
     240             :     static inline GDALm256i mm256name(__m128i x)                               \
     241             :     {                                                                          \
     242             :         GDALm256i reg;                                                         \
     243             :         reg.low = mm128name(x);                                                \
     244             :         reg.high = mm128name(_mm_srli_si128(x, 8));                            \
     245             :         return reg;                                                            \
     246             :     }
     247             : 
     248             : DEFINE_CVTE_MM256(GDALmm256_cvtepu8_epi16, GDALmm_cvtepu8_epi16)
     249             : DEFINE_CVTE_MM256(GDALmm256_cvtepu16_epi32, GDALmm_cvtepu16_epi32)
     250             : DEFINE_CVTE_MM256(GDALmm256_cvtepu16_epi64, GDALmm_cvtepu16_epi64)
     251             : DEFINE_CVTE_MM256(GDALmm256_cvtepu32_epi64, GDALmm_cvtepu32_epi64)
     252             : 
     253      513315 : static inline GDALm256i GDALmm256_srli_epi16(GDALm256i reg, int imm)
     254             : {
     255             :     GDALm256i ret;
     256      513315 :     ret.low = _mm_srli_epi16(reg.low, imm);
     257      513315 :     ret.high = _mm_srli_epi16(reg.high, imm);
     258      513315 :     return ret;
     259             : }
     260             : 
     261      188312 : static inline GDALm256i GDALmm256_srli_epi32(GDALm256i reg, int imm)
     262             : {
     263             :     GDALm256i ret;
     264      188312 :     ret.low = _mm_srli_epi32(reg.low, imm);
     265      188312 :     ret.high = _mm_srli_epi32(reg.high, imm);
     266      188312 :     return ret;
     267             : }
     268             : 
     269      188312 : static inline GDALm256i GDALmm256_srli_epi64(GDALm256i reg, int imm)
     270             : {
     271             :     GDALm256i ret;
     272      188312 :     ret.low = _mm_srli_epi64(reg.low, imm);
     273      188312 :     ret.high = _mm_srli_epi64(reg.high, imm);
     274      188312 :     return ret;
     275             : }
     276             : 
     277             : #endif
     278             : 
     279             : #endif /* GDAL_AVX2_EMULATION_H_INCLUDED */

Generated by: LCOV version 1.14