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