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 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 :
28 : #ifndef GDAL_AVX2_EMULATION_H_INCLUDED
29 : #define GDAL_AVX2_EMULATION_H_INCLUDED
30 :
31 : #include <emmintrin.h>
32 :
33 : #ifdef __SSE4_1__
34 : #include <smmintrin.h>
35 :
36 : #define GDALmm_min_epu16 _mm_min_epu16
37 : #define GDALmm_max_epu16 _mm_max_epu16
38 : #define GDALmm_mullo_epi32 _mm_mullo_epi32
39 : #define GDALmm_cvtepu8_epi16 _mm_cvtepu8_epi16
40 : #define GDALmm_cvtepu16_epi32 _mm_cvtepu16_epi32
41 : #define GDALmm_cvtepu16_epi64 _mm_cvtepu16_epi64
42 : #define GDALmm_cvtepu32_epi64 _mm_cvtepu32_epi64
43 :
44 : #else
45 : // Emulation of SSE4.1 _mm_min_epu16 and _mm_max_epu16 with SSE2 only
46 :
47 : static inline __m128i GDALAVX2Emul_mm_cmple_epu16(__m128i x, __m128i y)
48 : {
49 : return _mm_cmpeq_epi16(_mm_subs_epu16(x, y), _mm_setzero_si128());
50 : }
51 :
52 : static inline __m128i GDALAVX2Emul_mm_ternary(__m128i mask, __m128i then_reg,
53 : __m128i else_reg)
54 : {
55 : return _mm_or_si128(_mm_and_si128(mask, then_reg),
56 : _mm_andnot_si128(mask, else_reg));
57 : }
58 :
59 : static inline __m128i GDALmm_min_epu16(__m128i x, __m128i y)
60 : {
61 : const __m128i mask = GDALAVX2Emul_mm_cmple_epu16(x, y);
62 : return GDALAVX2Emul_mm_ternary(mask, x, y);
63 : }
64 :
65 : static inline __m128i GDALmm_max_epu16(__m128i x, __m128i y)
66 : {
67 : const __m128i mask = GDALAVX2Emul_mm_cmple_epu16(x, y);
68 : return GDALAVX2Emul_mm_ternary(mask, y, x);
69 : }
70 :
71 : static inline __m128i GDALmm_mullo_epi32(__m128i x, __m128i y)
72 : {
73 : const __m128i mul02 = _mm_shuffle_epi32(_mm_mul_epu32(x, y), 2 << 2);
74 : const __m128i mul13 = _mm_shuffle_epi32(
75 : _mm_mul_epu32(_mm_srli_si128(x, 4), _mm_srli_si128(y, 4)), 2 << 2);
76 : return _mm_unpacklo_epi32(mul02, mul13);
77 : ;
78 : }
79 :
80 : static inline __m128i GDALmm_cvtepu8_epi16(__m128i x)
81 : {
82 : return _mm_unpacklo_epi8(x, _mm_setzero_si128());
83 : }
84 :
85 : static inline __m128i GDALmm_cvtepu16_epi32(__m128i x)
86 : {
87 : return _mm_unpacklo_epi16(x, _mm_setzero_si128());
88 : }
89 :
90 : static inline __m128i GDALmm_cvtepu16_epi64(__m128i x)
91 : {
92 : return _mm_unpacklo_epi32(_mm_unpacklo_epi16(x, _mm_setzero_si128()),
93 : _mm_setzero_si128());
94 : }
95 :
96 : static inline __m128i GDALmm_cvtepu32_epi64(__m128i x)
97 : {
98 : return _mm_unpacklo_epi32(x, _mm_setzero_si128());
99 : }
100 :
101 : #endif // __SSE4_1__
102 :
103 : #ifdef __AVX2__
104 :
105 : #include <immintrin.h>
106 :
107 : typedef __m256i GDALm256i;
108 :
109 : #define GDALmm256_set1_epi8 _mm256_set1_epi8
110 : #define GDALmm256_set1_epi16 _mm256_set1_epi16
111 : #define GDALmm256_set1_epi32 _mm256_set1_epi32
112 : #define GDALmm256_setzero_si256 _mm256_setzero_si256
113 : #define GDALmm256_load_si256 _mm256_load_si256
114 : #define GDALmm256_store_si256 _mm256_store_si256
115 : #define GDALmm256_storeu_si256 _mm256_storeu_si256
116 : #define GDALmm256_cmpeq_epi8 _mm256_cmpeq_epi8
117 : #define GDALmm256_sad_epu8 _mm256_sad_epu8
118 : #define GDALmm256_add_epi32 _mm256_add_epi32
119 : #define GDALmm256_andnot_si256 _mm256_andnot_si256
120 : #define GDALmm256_and_si256 _mm256_and_si256
121 : #define GDALmm256_or_si256 _mm256_or_si256
122 : #define GDALmm256_min_epu8 _mm256_min_epu8
123 : #define GDALmm256_max_epu8 _mm256_max_epu8
124 : #define GDALmm256_extracti128_si256 _mm256_extracti128_si256
125 : #define GDALmm256_cvtepu8_epi16 _mm256_cvtepu8_epi16
126 : #define GDALmm256_madd_epi16 _mm256_madd_epi16
127 : #define GDALmm256_min_epu16 _mm256_min_epu16
128 : #define GDALmm256_max_epu16 _mm256_max_epu16
129 : #define GDALmm256_cvtepu16_epi32 _mm256_cvtepu16_epi32
130 : #define GDALmm256_cvtepu16_epi64 _mm256_cvtepu16_epi64
131 : #define GDALmm256_cvtepu32_epi64 _mm256_cvtepu32_epi64
132 : #define GDALmm256_mullo_epi32 _mm256_mullo_epi32
133 : #define GDALmm256_add_epi64 _mm256_add_epi64
134 : #define GDALmm256_add_epi16 _mm256_add_epi16
135 : #define GDALmm256_sub_epi16 _mm256_sub_epi16
136 : #define GDALmm256_min_epi16 _mm256_min_epi16
137 : #define GDALmm256_max_epi16 _mm256_max_epi16
138 : #define GDALmm256_srli_epi16 _mm256_srli_epi16
139 : #define GDALmm256_srli_epi32 _mm256_srli_epi32
140 : #define GDALmm256_srli_epi64 _mm256_srli_epi64
141 : #define GDALmm256_set1_epi64x _mm256_set1_epi64x
142 :
143 : #else
144 :
145 : typedef struct
146 : {
147 : __m128i low;
148 : __m128i high;
149 : } GDALm256i;
150 :
151 2480 : static inline GDALm256i GDALmm256_set1_epi8(char c)
152 : {
153 : GDALm256i reg;
154 2480 : reg.low = _mm_set1_epi8(c);
155 2480 : reg.high = _mm_set1_epi8(c);
156 2480 : return reg;
157 : }
158 :
159 21185 : static inline GDALm256i GDALmm256_set1_epi16(short s)
160 : {
161 : GDALm256i reg;
162 21185 : reg.low = _mm_set1_epi16(s);
163 21185 : reg.high = _mm_set1_epi16(s);
164 21185 : return reg;
165 : }
166 :
167 1048 : static inline GDALm256i GDALmm256_set1_epi32(int i)
168 : {
169 : GDALm256i reg;
170 1048 : reg.low = _mm_set1_epi32(i);
171 1048 : reg.high = _mm_set1_epi32(i);
172 1048 : return reg;
173 : }
174 :
175 1048 : static inline GDALm256i GDALmm256_set1_epi64x(long long i)
176 : {
177 : GDALm256i reg;
178 1048 : reg.low = _mm_set1_epi64x(i);
179 1048 : reg.high = _mm_set1_epi64x(i);
180 1048 : return reg;
181 : }
182 :
183 546017 : static inline GDALm256i GDALmm256_setzero_si256()
184 : {
185 : GDALm256i reg;
186 546017 : reg.low = _mm_setzero_si128();
187 546017 : reg.high = _mm_setzero_si128();
188 546017 : return reg;
189 : }
190 :
191 1595430 : static inline GDALm256i GDALmm256_load_si256(GDALm256i const *p)
192 : {
193 : GDALm256i reg;
194 1595430 : reg.low = _mm_load_si128(reinterpret_cast<__m128i const *>(p));
195 1595430 : reg.high = _mm_load_si128(reinterpret_cast<__m128i const *>(
196 : reinterpret_cast<const char *>(p) + 16));
197 1595430 : return reg;
198 : }
199 :
200 44535 : static inline void GDALmm256_store_si256(GDALm256i *p, GDALm256i reg)
201 : {
202 44535 : _mm_store_si128(reinterpret_cast<__m128i *>(p), reg.low);
203 44535 : _mm_store_si128(
204 : reinterpret_cast<__m128i *>(reinterpret_cast<char *>(p) + 16),
205 : reg.high);
206 44535 : }
207 :
208 2586 : static inline void GDALmm256_storeu_si256(GDALm256i *p, GDALm256i reg)
209 : {
210 2586 : _mm_storeu_si128(reinterpret_cast<__m128i *>(p), reg.low);
211 2586 : _mm_storeu_si128(
212 : reinterpret_cast<__m128i *>(reinterpret_cast<char *>(p) + 16),
213 : reg.high);
214 2586 : }
215 :
216 : #define DEFINE_BINARY_MM256(mm256name, mm128name) \
217 : static inline GDALm256i mm256name(GDALm256i r1, GDALm256i r2) \
218 : { \
219 : GDALm256i reg; \
220 : reg.low = mm128name(r1.low, r2.low); \
221 : reg.high = mm128name(r1.high, r2.high); \
222 : return reg; \
223 : }
224 :
225 37677 : DEFINE_BINARY_MM256(GDALmm256_cmpeq_epi8, _mm_cmpeq_epi8)
226 1507150 : DEFINE_BINARY_MM256(GDALmm256_sad_epu8, _mm_sad_epu8)
227 5078630 : DEFINE_BINARY_MM256(GDALmm256_add_epi32, _mm_add_epi32)
228 37677 : DEFINE_BINARY_MM256(GDALmm256_andnot_si256, _mm_andnot_si128)
229 2102400 : DEFINE_BINARY_MM256(GDALmm256_and_si256, _mm_and_si128)
230 24522 : DEFINE_BINARY_MM256(GDALmm256_or_si256, _mm_or_si128)
231 483966 : DEFINE_BINARY_MM256(GDALmm256_min_epu8, _mm_min_epu8)
232 1572040 : DEFINE_BINARY_MM256(GDALmm256_max_epu8, _mm_max_epu8)
233 3279350 : DEFINE_BINARY_MM256(GDALmm256_madd_epi16, _mm_madd_epi16)
234 : DEFINE_BINARY_MM256(GDALmm256_min_epu16, GDALmm_min_epu16)
235 : DEFINE_BINARY_MM256(GDALmm256_max_epu16, GDALmm_max_epu16)
236 : DEFINE_BINARY_MM256(GDALmm256_mullo_epi32, GDALmm_mullo_epi32)
237 584268 : DEFINE_BINARY_MM256(GDALmm256_add_epi64, _mm_add_epi64)
238 2871760 : DEFINE_BINARY_MM256(GDALmm256_add_epi16, _mm_add_epi16)
239 6042 : DEFINE_BINARY_MM256(GDALmm256_sub_epi16, _mm_sub_epi16)
240 2841560 : DEFINE_BINARY_MM256(GDALmm256_min_epi16, _mm_min_epi16)
241 2841560 : DEFINE_BINARY_MM256(GDALmm256_max_epi16, _mm_max_epi16)
242 :
243 : static inline __m128i GDALmm256_extracti128_si256(GDALm256i reg, int index)
244 : {
245 : return (index == 0) ? reg.low : reg.high;
246 : }
247 :
248 : #define DEFINE_CVTE_MM256(mm256name, mm128name) \
249 : static inline GDALm256i mm256name(__m128i x) \
250 : { \
251 : GDALm256i reg; \
252 : reg.low = mm128name(x); \
253 : reg.high = mm128name(_mm_srli_si128(x, 8)); \
254 : return reg; \
255 : }
256 :
257 : DEFINE_CVTE_MM256(GDALmm256_cvtepu8_epi16, GDALmm_cvtepu8_epi16)
258 : DEFINE_CVTE_MM256(GDALmm256_cvtepu16_epi32, GDALmm_cvtepu16_epi32)
259 : DEFINE_CVTE_MM256(GDALmm256_cvtepu16_epi64, GDALmm_cvtepu16_epi64)
260 : DEFINE_CVTE_MM256(GDALmm256_cvtepu32_epi64, GDALmm_cvtepu32_epi64)
261 :
262 497869 : static inline GDALm256i GDALmm256_srli_epi16(GDALm256i reg, int imm)
263 : {
264 : GDALm256i ret;
265 497869 : ret.low = _mm_srli_epi16(reg.low, imm);
266 497869 : ret.high = _mm_srli_epi16(reg.high, imm);
267 497869 : return ret;
268 : }
269 :
270 97378 : static inline GDALm256i GDALmm256_srli_epi32(GDALm256i reg, int imm)
271 : {
272 : GDALm256i ret;
273 97378 : ret.low = _mm_srli_epi32(reg.low, imm);
274 97378 : ret.high = _mm_srli_epi32(reg.high, imm);
275 97378 : return ret;
276 : }
277 :
278 97378 : static inline GDALm256i GDALmm256_srli_epi64(GDALm256i reg, int imm)
279 : {
280 : GDALm256i ret;
281 97378 : ret.low = _mm_srli_epi64(reg.low, imm);
282 97378 : ret.high = _mm_srli_epi64(reg.high, imm);
283 97378 : return ret;
284 : }
285 :
286 : #endif
287 :
288 : #endif /* GDAL_AVX2_EMULATION_H_INCLUDED */
|