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 : static inline __m128i GDALmm_cvtepu8_epi16(__m128i x)
71 : {
72 : return _mm_unpacklo_epi8(x, _mm_setzero_si128());
73 : }
74 :
75 : static inline __m128i GDALmm_cvtepu16_epi32(__m128i x)
76 : {
77 : return _mm_unpacklo_epi16(x, _mm_setzero_si128());
78 : }
79 :
80 : static inline __m128i GDALmm_cvtepu16_epi64(__m128i x)
81 : {
82 : return _mm_unpacklo_epi32(_mm_unpacklo_epi16(x, _mm_setzero_si128()),
83 : _mm_setzero_si128());
84 : }
85 :
86 : static inline __m128i GDALmm_cvtepu32_epi64(__m128i x)
87 : {
88 : return _mm_unpacklo_epi32(x, _mm_setzero_si128());
89 : }
90 :
91 : #endif // defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
92 :
93 : #ifdef __AVX2__
94 :
95 : #include <immintrin.h>
96 :
97 : typedef __m256i GDALm256i;
98 :
99 : #define GDALmm256_set1_epi8 _mm256_set1_epi8
100 : #define GDALmm256_set1_epi16 _mm256_set1_epi16
101 : #define GDALmm256_set1_epi32 _mm256_set1_epi32
102 : #define GDALmm256_setzero_si256 _mm256_setzero_si256
103 : #define GDALmm256_load_si256 _mm256_load_si256
104 : #define GDALmm256_store_si256 _mm256_store_si256
105 : #define GDALmm256_storeu_si256 _mm256_storeu_si256
106 : #define GDALmm256_cmpeq_epi8 _mm256_cmpeq_epi8
107 : #define GDALmm256_sad_epu8 _mm256_sad_epu8
108 : #define GDALmm256_add_epi32 _mm256_add_epi32
109 : #define GDALmm256_andnot_si256 _mm256_andnot_si256
110 : #define GDALmm256_and_si256 _mm256_and_si256
111 : #define GDALmm256_or_si256 _mm256_or_si256
112 : #define GDALmm256_min_epu8 _mm256_min_epu8
113 : #define GDALmm256_max_epu8 _mm256_max_epu8
114 : #define GDALmm256_extracti128_si256 _mm256_extracti128_si256
115 : #define GDALmm256_cvtepu8_epi16 _mm256_cvtepu8_epi16
116 : #define GDALmm256_madd_epi16 _mm256_madd_epi16
117 : #define GDALmm256_min_epu16 _mm256_min_epu16
118 : #define GDALmm256_max_epu16 _mm256_max_epu16
119 : #define GDALmm256_cvtepu16_epi32 _mm256_cvtepu16_epi32
120 : #define GDALmm256_cvtepu16_epi64 _mm256_cvtepu16_epi64
121 : #define GDALmm256_cvtepu32_epi64 _mm256_cvtepu32_epi64
122 : #define GDALmm256_mullo_epi32 _mm256_mullo_epi32
123 : #define GDALmm256_add_epi64 _mm256_add_epi64
124 : #define GDALmm256_add_epi16 _mm256_add_epi16
125 : #define GDALmm256_sub_epi16 _mm256_sub_epi16
126 : #define GDALmm256_min_epi16 _mm256_min_epi16
127 : #define GDALmm256_max_epi16 _mm256_max_epi16
128 : #define GDALmm256_srli_epi16 _mm256_srli_epi16
129 : #define GDALmm256_srli_epi32 _mm256_srli_epi32
130 : #define GDALmm256_srli_epi64 _mm256_srli_epi64
131 : #define GDALmm256_set1_epi64x _mm256_set1_epi64x
132 :
133 : #else
134 :
135 : typedef struct
136 : {
137 : __m128i low;
138 : __m128i high;
139 : } GDALm256i;
140 :
141 2984 : static inline GDALm256i GDALmm256_set1_epi8(char c)
142 : {
143 : GDALm256i reg;
144 2984 : reg.low = _mm_set1_epi8(c);
145 2984 : reg.high = _mm_set1_epi8(c);
146 2984 : return reg;
147 : }
148 :
149 25769 : static inline GDALm256i GDALmm256_set1_epi16(short s)
150 : {
151 : GDALm256i reg;
152 25769 : reg.low = _mm_set1_epi16(s);
153 25769 : reg.high = _mm_set1_epi16(s);
154 25769 : return reg;
155 : }
156 :
157 1852 : static inline GDALm256i GDALmm256_set1_epi32(int i)
158 : {
159 : GDALm256i reg;
160 1852 : reg.low = _mm_set1_epi32(i);
161 1852 : reg.high = _mm_set1_epi32(i);
162 1852 : return reg;
163 : }
164 :
165 1852 : static inline GDALm256i GDALmm256_set1_epi64x(long long i)
166 : {
167 : GDALm256i reg;
168 1852 : reg.low = _mm_set1_epi64x(i);
169 1852 : reg.high = _mm_set1_epi64x(i);
170 1852 : return reg;
171 : }
172 :
173 608230 : static inline GDALm256i GDALmm256_setzero_si256()
174 : {
175 : GDALm256i reg;
176 608230 : reg.low = _mm_setzero_si128();
177 608230 : reg.high = _mm_setzero_si128();
178 608230 : return reg;
179 : }
180 :
181 1912460 : static inline GDALm256i GDALmm256_load_si256(GDALm256i const *p)
182 : {
183 : GDALm256i reg;
184 1912460 : reg.low = _mm_load_si128(reinterpret_cast<__m128i const *>(p));
185 1912460 : reg.high = _mm_load_si128(reinterpret_cast<__m128i const *>(
186 : reinterpret_cast<const char *>(p) + 16));
187 1912460 : return reg;
188 : }
189 :
190 52245 : static inline void GDALmm256_store_si256(GDALm256i *p, GDALm256i reg)
191 : {
192 52245 : _mm_store_si128(reinterpret_cast<__m128i *>(p), reg.low);
193 52245 : _mm_store_si128(
194 : reinterpret_cast<__m128i *>(reinterpret_cast<char *>(p) + 16),
195 : reg.high);
196 52245 : }
197 :
198 4696 : static inline void GDALmm256_storeu_si256(GDALm256i *p, GDALm256i reg)
199 : {
200 4696 : _mm_storeu_si128(reinterpret_cast<__m128i *>(p), reg.low);
201 4696 : _mm_storeu_si128(
202 : reinterpret_cast<__m128i *>(reinterpret_cast<char *>(p) + 16),
203 : reg.high);
204 4696 : }
205 :
206 : #define DEFINE_BINARY_MM256(mm256name, mm128name) \
207 : static inline GDALm256i mm256name(GDALm256i r1, GDALm256i r2) \
208 : { \
209 : GDALm256i reg; \
210 : reg.low = mm128name(r1.low, r2.low); \
211 : reg.high = mm128name(r1.high, r2.high); \
212 : return reg; \
213 : }
214 :
215 52470 : DEFINE_BINARY_MM256(GDALmm256_cmpeq_epi8, _mm_cmpeq_epi8)
216 1665530 : DEFINE_BINARY_MM256(GDALmm256_sad_epu8, _mm_sad_epu8)
217 6403070 : DEFINE_BINARY_MM256(GDALmm256_add_epi32, _mm_add_epi32)
218 52470 : DEFINE_BINARY_MM256(GDALmm256_andnot_si256, _mm_andnot_si128)
219 3125620 : DEFINE_BINARY_MM256(GDALmm256_and_si256, _mm_and_si128)
220 26160 : DEFINE_BINARY_MM256(GDALmm256_or_si256, _mm_or_si128)
221 926307 : DEFINE_BINARY_MM256(GDALmm256_min_epu8, _mm_min_epu8)
222 1997790 : DEFINE_BINARY_MM256(GDALmm256_max_epu8, _mm_max_epu8)
223 4006850 : DEFINE_BINARY_MM256(GDALmm256_madd_epi16, _mm_madd_epi16)
224 : DEFINE_BINARY_MM256(GDALmm256_min_epu16, GDALmm_min_epu16)
225 : DEFINE_BINARY_MM256(GDALmm256_max_epu16, GDALmm_max_epu16)
226 : DEFINE_BINARY_MM256(GDALmm256_mullo_epi32, GDALmm_mullo_epi32)
227 1461370 : DEFINE_BINARY_MM256(GDALmm256_add_epi64, _mm_add_epi64)
228 3337300 : DEFINE_BINARY_MM256(GDALmm256_add_epi16, _mm_add_epi16)
229 10620 : DEFINE_BINARY_MM256(GDALmm256_sub_epi16, _mm_sub_epi16)
230 3277630 : DEFINE_BINARY_MM256(GDALmm256_min_epi16, _mm_min_epi16)
231 3277630 : DEFINE_BINARY_MM256(GDALmm256_max_epi16, _mm_max_epi16)
232 :
233 : static inline __m128i GDALmm256_extracti128_si256(GDALm256i reg, int index)
234 : {
235 : return (index == 0) ? reg.low : reg.high;
236 : }
237 :
238 : #define DEFINE_CVTE_MM256(mm256name, mm128name) \
239 : static inline GDALm256i mm256name(__m128i x) \
240 : { \
241 : GDALm256i reg; \
242 : reg.low = mm128name(x); \
243 : reg.high = mm128name(_mm_srli_si128(x, 8)); \
244 : return reg; \
245 : }
246 :
247 : DEFINE_CVTE_MM256(GDALmm256_cvtepu8_epi16, GDALmm_cvtepu8_epi16)
248 : DEFINE_CVTE_MM256(GDALmm256_cvtepu16_epi32, GDALmm_cvtepu16_epi32)
249 : DEFINE_CVTE_MM256(GDALmm256_cvtepu16_epi64, GDALmm_cvtepu16_epi64)
250 : DEFINE_CVTE_MM256(GDALmm256_cvtepu32_epi64, GDALmm_cvtepu32_epi64)
251 :
252 546028 : static inline GDALm256i GDALmm256_srli_epi16(GDALm256i reg, int imm)
253 : {
254 : GDALm256i ret;
255 546028 : ret.low = _mm_srli_epi16(reg.low, imm);
256 546028 : ret.high = _mm_srli_epi16(reg.high, imm);
257 546028 : return ret;
258 : }
259 :
260 243562 : static inline GDALm256i GDALmm256_srli_epi32(GDALm256i reg, int imm)
261 : {
262 : GDALm256i ret;
263 243562 : ret.low = _mm_srli_epi32(reg.low, imm);
264 243562 : ret.high = _mm_srli_epi32(reg.high, imm);
265 243562 : return ret;
266 : }
267 :
268 243562 : static inline GDALm256i GDALmm256_srli_epi64(GDALm256i reg, int imm)
269 : {
270 : GDALm256i ret;
271 243562 : ret.low = _mm_srli_epi64(reg.low, imm);
272 243562 : ret.high = _mm_srli_epi64(reg.high, imm);
273 243562 : return ret;
274 : }
275 :
276 : #endif
277 :
278 : #endif /* GDAL_AVX2_EMULATION_H_INCLUDED */
|