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 */
|