Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: SSE2 helper
5 : * Author: Even Rouault <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #ifndef GDALSSE_PRIV_H_INCLUDED
14 : #define GDALSSE_PRIV_H_INCLUDED
15 :
16 : #ifndef DOXYGEN_SKIP
17 :
18 : #include "cpl_port.h"
19 :
20 : /* We restrict to 64bit processors because they are guaranteed to have SSE2 */
21 : /* Could possibly be used too on 32bit, but we would need to check at runtime */
22 : #if (defined(__x86_64) || defined(_M_X64) || defined(USE_SSE2)) && \
23 : !defined(USE_SSE2_EMULATION)
24 :
25 : #include <string.h>
26 :
27 : #ifdef USE_NEON_OPTIMIZATIONS
28 : #include "include_sse2neon.h"
29 : #else
30 : /* Requires SSE2 */
31 : #include <emmintrin.h>
32 :
33 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
34 : #include <smmintrin.h>
35 : #endif
36 : #endif
37 :
38 : #include "gdal_priv_templates.hpp"
39 :
40 523196 : static inline __m128i GDALCopyInt16ToXMM(const void *ptr)
41 : {
42 : unsigned short s;
43 523196 : memcpy(&s, ptr, 2);
44 1046390 : return _mm_cvtsi32_si128(s);
45 : }
46 :
47 225634165 : static inline __m128i GDALCopyInt32ToXMM(const void *ptr)
48 : {
49 : GInt32 i;
50 225634165 : memcpy(&i, ptr, 4);
51 451268340 : return _mm_cvtsi32_si128(i);
52 : }
53 :
54 768 : static inline __m128i GDALCopyInt64ToXMM(const void *ptr)
55 : {
56 : #if defined(__i386__) || defined(_M_IX86)
57 : return _mm_loadl_epi64(static_cast<const __m128i *>(ptr));
58 : #else
59 : GInt64 i;
60 768 : memcpy(&i, ptr, 8);
61 1536 : return _mm_cvtsi64_si128(i);
62 : #endif
63 : }
64 :
65 : static inline void GDALCopyXMMToInt16(const __m128i xmm, void *pDest)
66 : {
67 : GInt16 i = static_cast<GInt16>(_mm_extract_epi16(xmm, 0));
68 : memcpy(pDest, &i, 2);
69 : }
70 :
71 : class XMMReg2Double
72 : {
73 : public:
74 : __m128d xmm;
75 :
76 : #if defined(__GNUC__)
77 : #pragma GCC diagnostic push
78 : #pragma GCC diagnostic ignored "-Weffc++"
79 : #endif
80 : /* coverity[uninit_member] */
81 : XMMReg2Double() = default;
82 : #if defined(__GNUC__)
83 : #pragma GCC diagnostic pop
84 : #endif
85 :
86 : XMMReg2Double(double val) : xmm(_mm_load_sd(&val))
87 : {
88 : }
89 :
90 2615130 : XMMReg2Double(const XMMReg2Double &other) : xmm(other.xmm)
91 : {
92 2615130 : }
93 :
94 1841080 : static inline XMMReg2Double Zero()
95 : {
96 : XMMReg2Double reg;
97 1841080 : reg.Zeroize();
98 1841080 : return reg;
99 : }
100 :
101 : static inline XMMReg2Double Load1ValHighAndLow(const double *ptr)
102 : {
103 : XMMReg2Double reg;
104 : reg.nsLoad1ValHighAndLow(ptr);
105 : return reg;
106 : }
107 :
108 142911 : static inline XMMReg2Double Load2Val(const double *ptr)
109 : {
110 : XMMReg2Double reg;
111 142911 : reg.nsLoad2Val(ptr);
112 142911 : return reg;
113 : }
114 :
115 768 : static inline XMMReg2Double Load2Val(const float *ptr)
116 : {
117 : XMMReg2Double reg;
118 768 : reg.nsLoad2Val(ptr);
119 768 : return reg;
120 : }
121 :
122 23013400 : static inline XMMReg2Double Load2ValAligned(const double *ptr)
123 : {
124 : XMMReg2Double reg;
125 23013400 : reg.nsLoad2ValAligned(ptr);
126 23013400 : return reg;
127 : }
128 :
129 523196 : static inline XMMReg2Double Load2Val(const unsigned char *ptr)
130 : {
131 : XMMReg2Double reg;
132 523196 : reg.nsLoad2Val(ptr);
133 523196 : return reg;
134 : }
135 :
136 18492 : static inline XMMReg2Double Load2Val(const short *ptr)
137 : {
138 : XMMReg2Double reg;
139 18492 : reg.nsLoad2Val(ptr);
140 18492 : return reg;
141 : }
142 :
143 29184 : static inline XMMReg2Double Load2Val(const unsigned short *ptr)
144 : {
145 : XMMReg2Double reg;
146 29184 : reg.nsLoad2Val(ptr);
147 29184 : return reg;
148 : }
149 :
150 2 : static inline XMMReg2Double Equals(const XMMReg2Double &expr1,
151 : const XMMReg2Double &expr2)
152 : {
153 : XMMReg2Double reg;
154 2 : reg.xmm = _mm_cmpeq_pd(expr1.xmm, expr2.xmm);
155 2 : return reg;
156 : }
157 :
158 2612332 : static inline XMMReg2Double NotEquals(const XMMReg2Double &expr1,
159 : const XMMReg2Double &expr2)
160 : {
161 : XMMReg2Double reg;
162 2612332 : reg.xmm = _mm_cmpneq_pd(expr1.xmm, expr2.xmm);
163 2609112 : return reg;
164 : }
165 :
166 6 : static inline XMMReg2Double Greater(const XMMReg2Double &expr1,
167 : const XMMReg2Double &expr2)
168 : {
169 : XMMReg2Double reg;
170 6 : reg.xmm = _mm_cmpgt_pd(expr1.xmm, expr2.xmm);
171 6 : return reg;
172 : }
173 :
174 2600190 : static inline XMMReg2Double And(const XMMReg2Double &expr1,
175 : const XMMReg2Double &expr2)
176 : {
177 : XMMReg2Double reg;
178 2600190 : reg.xmm = _mm_and_pd(expr1.xmm, expr2.xmm);
179 2610540 : return reg;
180 : }
181 :
182 2 : static inline XMMReg2Double Ternary(const XMMReg2Double &cond,
183 : const XMMReg2Double &true_expr,
184 : const XMMReg2Double &false_expr)
185 : {
186 : XMMReg2Double reg;
187 4 : reg.xmm = _mm_or_pd(_mm_and_pd(cond.xmm, true_expr.xmm),
188 2 : _mm_andnot_pd(cond.xmm, false_expr.xmm));
189 2 : return reg;
190 : }
191 :
192 7855072 : static inline XMMReg2Double Min(const XMMReg2Double &expr1,
193 : const XMMReg2Double &expr2)
194 : {
195 : XMMReg2Double reg;
196 7855072 : reg.xmm = _mm_min_pd(expr1.xmm, expr2.xmm);
197 7968822 : return reg;
198 : }
199 :
200 71028901 : inline void nsLoad1ValHighAndLow(const double *ptr)
201 : {
202 71028901 : xmm = _mm_load1_pd(ptr);
203 71028901 : }
204 :
205 338252017 : inline void nsLoad2Val(const double *ptr)
206 : {
207 338252017 : xmm = _mm_loadu_pd(ptr);
208 338252017 : }
209 :
210 108741000 : inline void nsLoad2ValAligned(const double *ptr)
211 : {
212 108741000 : xmm = _mm_load_pd(ptr);
213 108741000 : }
214 :
215 768 : inline void nsLoad2Val(const float *ptr)
216 : {
217 1536 : xmm = _mm_cvtps_pd(_mm_castsi128_ps(GDALCopyInt64ToXMM(ptr)));
218 768 : }
219 :
220 523196 : inline void nsLoad2Val(const unsigned char *ptr)
221 : {
222 523196 : __m128i xmm_i = GDALCopyInt16ToXMM(ptr);
223 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
224 : xmm_i = _mm_cvtepu8_epi32(xmm_i);
225 : #else
226 1046390 : xmm_i = _mm_unpacklo_epi8(xmm_i, _mm_setzero_si128());
227 1046390 : xmm_i = _mm_unpacklo_epi16(xmm_i, _mm_setzero_si128());
228 : #endif
229 523196 : xmm = _mm_cvtepi32_pd(xmm_i);
230 523196 : }
231 :
232 2046162 : inline void nsLoad2Val(const short *ptr)
233 : {
234 2046162 : __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
235 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
236 : xmm_i = _mm_cvtepi16_epi32(xmm_i);
237 : #else
238 2046162 : xmm_i = _mm_unpacklo_epi16(
239 : xmm_i, xmm_i); /* 0|0|0|0|0|0|b|a --> 0|0|0|0|b|b|a|a */
240 2046162 : xmm_i = _mm_srai_epi32(
241 : xmm_i, 16); /* 0|0|0|0|b|b|a|a --> 0|0|0|0|sign(b)|b|sign(a)|a */
242 : #endif
243 2046162 : xmm = _mm_cvtepi32_pd(xmm_i);
244 2046162 : }
245 :
246 43617702 : inline void nsLoad2Val(const unsigned short *ptr)
247 : {
248 43617702 : __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
249 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
250 : xmm_i = _mm_cvtepu16_epi32(xmm_i);
251 : #else
252 87474304 : xmm_i = _mm_unpacklo_epi16(
253 : xmm_i,
254 : _mm_setzero_si128()); /* 0|0|0|0|0|0|b|a --> 0|0|0|0|0|b|0|a */
255 : #endif
256 43930102 : xmm = _mm_cvtepi32_pd(xmm_i);
257 43930102 : }
258 :
259 180261001 : static inline void Load4Val(const unsigned char *ptr, XMMReg2Double &low,
260 : XMMReg2Double &high)
261 : {
262 180261001 : __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
263 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
264 : xmm_i = _mm_cvtepu8_epi32(xmm_i);
265 : #else
266 361008002 : xmm_i = _mm_unpacklo_epi8(xmm_i, _mm_setzero_si128());
267 361249002 : xmm_i = _mm_unpacklo_epi16(xmm_i, _mm_setzero_si128());
268 : #endif
269 180590001 : low.xmm = _mm_cvtepi32_pd(xmm_i);
270 180850001 : high.xmm =
271 180590001 : _mm_cvtepi32_pd(_mm_shuffle_epi32(xmm_i, _MM_SHUFFLE(3, 2, 3, 2)));
272 180850001 : }
273 :
274 : static inline void Load4Val(const short *ptr, XMMReg2Double &low,
275 : XMMReg2Double &high)
276 : {
277 : low.nsLoad2Val(ptr);
278 : high.nsLoad2Val(ptr + 2);
279 : }
280 :
281 : static inline void Load4Val(const unsigned short *ptr, XMMReg2Double &low,
282 : XMMReg2Double &high)
283 : {
284 : low.nsLoad2Val(ptr);
285 : high.nsLoad2Val(ptr + 2);
286 : }
287 :
288 : static inline void Load4Val(const double *ptr, XMMReg2Double &low,
289 : XMMReg2Double &high)
290 : {
291 : low.nsLoad2Val(ptr);
292 : high.nsLoad2Val(ptr + 2);
293 : }
294 :
295 37633 : static inline void Load4Val(const float *ptr, XMMReg2Double &low,
296 : XMMReg2Double &high)
297 : {
298 37633 : __m128 temp1 = _mm_loadu_ps(ptr);
299 37633 : __m128 temp2 = _mm_shuffle_ps(temp1, temp1, _MM_SHUFFLE(3, 2, 3, 2));
300 37633 : low.xmm = _mm_cvtps_pd(temp1);
301 37633 : high.xmm = _mm_cvtps_pd(temp2);
302 37633 : }
303 :
304 288115000 : inline void Zeroize()
305 : {
306 288115000 : xmm = _mm_setzero_pd();
307 288115000 : }
308 :
309 809514037 : inline XMMReg2Double &operator=(const XMMReg2Double &other)
310 : {
311 809514037 : xmm = other.xmm;
312 809514037 : return *this;
313 : }
314 :
315 619811003 : inline XMMReg2Double &operator+=(const XMMReg2Double &other)
316 : {
317 619811003 : xmm = _mm_add_pd(xmm, other.xmm);
318 619811003 : return *this;
319 : }
320 :
321 21021702 : inline XMMReg2Double &operator*=(const XMMReg2Double &other)
322 : {
323 21021702 : xmm = _mm_mul_pd(xmm, other.xmm);
324 21021702 : return *this;
325 : }
326 :
327 142917009 : inline XMMReg2Double operator+(const XMMReg2Double &other) const
328 : {
329 : XMMReg2Double ret;
330 142917009 : ret.xmm = _mm_add_pd(xmm, other.xmm);
331 142917009 : return ret;
332 : }
333 :
334 2 : inline XMMReg2Double operator-(const XMMReg2Double &other) const
335 : {
336 : XMMReg2Double ret;
337 2 : ret.xmm = _mm_sub_pd(xmm, other.xmm);
338 2 : return ret;
339 : }
340 :
341 672575002 : inline XMMReg2Double operator*(const XMMReg2Double &other) const
342 : {
343 : XMMReg2Double ret;
344 672575002 : ret.xmm = _mm_mul_pd(xmm, other.xmm);
345 672575002 : return ret;
346 : }
347 :
348 2611942 : inline XMMReg2Double operator/(const XMMReg2Double &other) const
349 : {
350 : XMMReg2Double ret;
351 2611942 : ret.xmm = _mm_div_pd(xmm, other.xmm);
352 2611942 : return ret;
353 : }
354 :
355 144348001 : inline double GetHorizSum() const
356 : {
357 : __m128d xmm2;
358 144348001 : xmm2 = _mm_shuffle_pd(
359 : xmm, xmm,
360 : _MM_SHUFFLE2(0, 1)); /* transfer high word into low word of xmm2 */
361 434412003 : return _mm_cvtsd_f64(_mm_add_sd(xmm, xmm2));
362 : }
363 :
364 32 : inline void Store2Val(double *ptr) const
365 : {
366 32 : _mm_storeu_pd(ptr, xmm);
367 32 : }
368 :
369 : inline void Store2ValAligned(double *ptr) const
370 : {
371 : _mm_store_pd(ptr, xmm);
372 : }
373 :
374 74046302 : inline void Store2Val(float *ptr) const
375 : {
376 148175004 : __m128i xmm_i = _mm_castps_si128(_mm_cvtpd_ps(xmm));
377 74128702 : GDALCopyXMMToInt64(xmm_i, reinterpret_cast<GInt64 *>(ptr));
378 74003702 : }
379 :
380 : inline void Store2Val(unsigned char *ptr) const
381 : {
382 : __m128i tmp = _mm_cvttpd_epi32(_mm_add_pd(
383 : xmm,
384 : _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
385 : tmp = _mm_packs_epi32(tmp, tmp);
386 : tmp = _mm_packus_epi16(tmp, tmp);
387 : GDALCopyXMMToInt16(tmp, reinterpret_cast<GInt16 *>(ptr));
388 : }
389 :
390 4710772 : inline void Store2Val(unsigned short *ptr) const
391 : {
392 4710772 : __m128i tmp = _mm_cvttpd_epi32(_mm_add_pd(
393 4710772 : xmm,
394 : _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
395 : // X X X X 0 B 0 A --> X X X X A A B A
396 4755012 : tmp = _mm_shufflelo_epi16(tmp, 0 | (2 << 2));
397 4855352 : GDALCopyXMMToInt32(tmp, reinterpret_cast<GInt32 *>(ptr));
398 4803172 : }
399 :
400 8 : inline void StoreMask(unsigned char *ptr) const
401 : {
402 8 : _mm_storeu_si128(reinterpret_cast<__m128i *>(ptr),
403 8 : _mm_castpd_si128(xmm));
404 8 : }
405 :
406 : inline operator double() const
407 : {
408 : return _mm_cvtsd_f64(xmm);
409 : }
410 : };
411 :
412 : #else
413 :
414 : #ifndef NO_WARN_USE_SSE2_EMULATION
415 : #warning "Software emulation of SSE2 !"
416 : #endif
417 :
418 : class XMMReg2Double
419 : {
420 : public:
421 : double low;
422 : double high;
423 :
424 84 : XMMReg2Double()
425 84 : {
426 84 : }
427 :
428 : XMMReg2Double(double val)
429 : {
430 : low = val;
431 : high = 0.0;
432 : }
433 :
434 : XMMReg2Double(const XMMReg2Double &other) : low(other.low), high(other.high)
435 : {
436 : }
437 :
438 : static inline XMMReg2Double Zero()
439 : {
440 : XMMReg2Double reg;
441 : reg.Zeroize();
442 : return reg;
443 : }
444 :
445 : static inline XMMReg2Double Load1ValHighAndLow(const double *ptr)
446 : {
447 : XMMReg2Double reg;
448 : reg.nsLoad1ValHighAndLow(ptr);
449 : return reg;
450 : }
451 :
452 2 : static inline XMMReg2Double Equals(const XMMReg2Double &expr1,
453 : const XMMReg2Double &expr2)
454 : {
455 2 : XMMReg2Double reg;
456 :
457 2 : if (expr1.low == expr2.low)
458 2 : memset(&(reg.low), 0xFF, sizeof(double));
459 : else
460 0 : reg.low = 0;
461 :
462 2 : if (expr1.high == expr2.high)
463 2 : memset(&(reg.high), 0xFF, sizeof(double));
464 : else
465 0 : reg.high = 0;
466 :
467 2 : return reg;
468 : }
469 :
470 2 : static inline XMMReg2Double NotEquals(const XMMReg2Double &expr1,
471 : const XMMReg2Double &expr2)
472 : {
473 2 : XMMReg2Double reg;
474 :
475 2 : if (expr1.low != expr2.low)
476 0 : memset(&(reg.low), 0xFF, sizeof(double));
477 : else
478 2 : reg.low = 0;
479 :
480 2 : if (expr1.high != expr2.high)
481 0 : memset(&(reg.high), 0xFF, sizeof(double));
482 : else
483 2 : reg.high = 0;
484 :
485 2 : return reg;
486 : }
487 :
488 6 : static inline XMMReg2Double Greater(const XMMReg2Double &expr1,
489 : const XMMReg2Double &expr2)
490 : {
491 6 : XMMReg2Double reg;
492 :
493 6 : if (expr1.low > expr2.low)
494 2 : memset(&(reg.low), 0xFF, sizeof(double));
495 : else
496 4 : reg.low = 0;
497 :
498 6 : if (expr1.high > expr2.high)
499 2 : memset(&(reg.high), 0xFF, sizeof(double));
500 : else
501 4 : reg.high = 0;
502 :
503 6 : return reg;
504 : }
505 :
506 : static inline XMMReg2Double And(const XMMReg2Double &expr1,
507 : const XMMReg2Double &expr2)
508 : {
509 : XMMReg2Double reg;
510 : int low1[2], high1[2];
511 : int low2[2], high2[2];
512 : memcpy(low1, &expr1.low, sizeof(double));
513 : memcpy(high1, &expr1.high, sizeof(double));
514 : memcpy(low2, &expr2.low, sizeof(double));
515 : memcpy(high2, &expr2.high, sizeof(double));
516 : low1[0] &= low2[0];
517 : low1[1] &= low2[1];
518 : high1[0] &= high2[0];
519 : high1[1] &= high2[1];
520 : memcpy(®.low, low1, sizeof(double));
521 : memcpy(®.high, high1, sizeof(double));
522 : return reg;
523 : }
524 :
525 2 : static inline XMMReg2Double Ternary(const XMMReg2Double &cond,
526 : const XMMReg2Double &true_expr,
527 : const XMMReg2Double &false_expr)
528 : {
529 2 : XMMReg2Double reg;
530 2 : if (cond.low != 0)
531 1 : reg.low = true_expr.low;
532 : else
533 1 : reg.low = false_expr.low;
534 2 : if (cond.high != 0)
535 1 : reg.high = true_expr.high;
536 : else
537 1 : reg.high = false_expr.high;
538 2 : return reg;
539 : }
540 :
541 2 : static inline XMMReg2Double Min(const XMMReg2Double &expr1,
542 : const XMMReg2Double &expr2)
543 : {
544 2 : XMMReg2Double reg;
545 2 : reg.low = (expr1.low < expr2.low) ? expr1.low : expr2.low;
546 2 : reg.high = (expr1.high < expr2.high) ? expr1.high : expr2.high;
547 2 : return reg;
548 : }
549 :
550 1 : static inline XMMReg2Double Load2Val(const double *ptr)
551 : {
552 1 : XMMReg2Double reg;
553 1 : reg.nsLoad2Val(ptr);
554 1 : return reg;
555 : }
556 :
557 : static inline XMMReg2Double Load2ValAligned(const double *ptr)
558 : {
559 : XMMReg2Double reg;
560 : reg.nsLoad2ValAligned(ptr);
561 : return reg;
562 : }
563 :
564 : static inline XMMReg2Double Load2Val(const float *ptr)
565 : {
566 : XMMReg2Double reg;
567 : reg.nsLoad2Val(ptr);
568 : return reg;
569 : }
570 :
571 : static inline XMMReg2Double Load2Val(const unsigned char *ptr)
572 : {
573 : XMMReg2Double reg;
574 : reg.nsLoad2Val(ptr);
575 : return reg;
576 : }
577 :
578 : static inline XMMReg2Double Load2Val(const short *ptr)
579 : {
580 : XMMReg2Double reg;
581 : reg.nsLoad2Val(ptr);
582 : return reg;
583 : }
584 :
585 : static inline XMMReg2Double Load2Val(const unsigned short *ptr)
586 : {
587 : XMMReg2Double reg;
588 : reg.nsLoad2Val(ptr);
589 : return reg;
590 : }
591 :
592 1 : inline void nsLoad1ValHighAndLow(const double *ptr)
593 : {
594 1 : low = ptr[0];
595 1 : high = ptr[0];
596 1 : }
597 :
598 17 : inline void nsLoad2Val(const double *ptr)
599 : {
600 17 : low = ptr[0];
601 17 : high = ptr[1];
602 17 : }
603 :
604 : inline void nsLoad2ValAligned(const double *ptr)
605 : {
606 : low = ptr[0];
607 : high = ptr[1];
608 : }
609 :
610 2 : inline void nsLoad2Val(const float *ptr)
611 : {
612 2 : low = ptr[0];
613 2 : high = ptr[1];
614 2 : }
615 :
616 : inline void nsLoad2Val(const unsigned char *ptr)
617 : {
618 : low = ptr[0];
619 : high = ptr[1];
620 : }
621 :
622 2 : inline void nsLoad2Val(const short *ptr)
623 : {
624 2 : low = ptr[0];
625 2 : high = ptr[1];
626 2 : }
627 :
628 2 : inline void nsLoad2Val(const unsigned short *ptr)
629 : {
630 2 : low = ptr[0];
631 2 : high = ptr[1];
632 2 : }
633 :
634 1 : static inline void Load4Val(const unsigned char *ptr, XMMReg2Double &low,
635 : XMMReg2Double &high)
636 : {
637 1 : low.low = ptr[0];
638 1 : low.high = ptr[1];
639 1 : high.low = ptr[2];
640 1 : high.high = ptr[3];
641 1 : }
642 :
643 : static inline void Load4Val(const short *ptr, XMMReg2Double &low,
644 : XMMReg2Double &high)
645 : {
646 : low.nsLoad2Val(ptr);
647 : high.nsLoad2Val(ptr + 2);
648 : }
649 :
650 : static inline void Load4Val(const unsigned short *ptr, XMMReg2Double &low,
651 : XMMReg2Double &high)
652 : {
653 : low.nsLoad2Val(ptr);
654 : high.nsLoad2Val(ptr + 2);
655 : }
656 :
657 : static inline void Load4Val(const double *ptr, XMMReg2Double &low,
658 : XMMReg2Double &high)
659 : {
660 : low.nsLoad2Val(ptr);
661 : high.nsLoad2Val(ptr + 2);
662 : }
663 :
664 1 : static inline void Load4Val(const float *ptr, XMMReg2Double &low,
665 : XMMReg2Double &high)
666 : {
667 1 : low.nsLoad2Val(ptr);
668 1 : high.nsLoad2Val(ptr + 2);
669 1 : }
670 :
671 : inline void Zeroize()
672 : {
673 : low = 0.0;
674 : high = 0.0;
675 : }
676 :
677 37 : inline XMMReg2Double &operator=(const XMMReg2Double &other)
678 : {
679 37 : low = other.low;
680 37 : high = other.high;
681 37 : return *this;
682 : }
683 :
684 3 : inline XMMReg2Double &operator+=(const XMMReg2Double &other)
685 : {
686 3 : low += other.low;
687 3 : high += other.high;
688 3 : return *this;
689 : }
690 :
691 2 : inline XMMReg2Double &operator*=(const XMMReg2Double &other)
692 : {
693 2 : low *= other.low;
694 2 : high *= other.high;
695 2 : return *this;
696 : }
697 :
698 9 : inline XMMReg2Double operator+(const XMMReg2Double &other) const
699 : {
700 9 : XMMReg2Double ret;
701 9 : ret.low = low + other.low;
702 9 : ret.high = high + other.high;
703 9 : return ret;
704 : }
705 :
706 2 : inline XMMReg2Double operator-(const XMMReg2Double &other) const
707 : {
708 2 : XMMReg2Double ret;
709 2 : ret.low = low - other.low;
710 2 : ret.high = high - other.high;
711 2 : return ret;
712 : }
713 :
714 2 : inline XMMReg2Double operator*(const XMMReg2Double &other) const
715 : {
716 2 : XMMReg2Double ret;
717 2 : ret.low = low * other.low;
718 2 : ret.high = high * other.high;
719 2 : return ret;
720 : }
721 :
722 2 : inline XMMReg2Double operator/(const XMMReg2Double &other) const
723 : {
724 2 : XMMReg2Double ret;
725 2 : ret.low = low / other.low;
726 2 : ret.high = high / other.high;
727 2 : return ret;
728 : }
729 :
730 1 : inline double GetHorizSum() const
731 : {
732 1 : return low + high;
733 : }
734 :
735 32 : inline void Store2Val(double *ptr) const
736 : {
737 32 : ptr[0] = low;
738 32 : ptr[1] = high;
739 32 : }
740 :
741 : inline void Store2ValAligned(double *ptr) const
742 : {
743 : ptr[0] = low;
744 : ptr[1] = high;
745 : }
746 :
747 2 : inline void Store2Val(float *ptr) const
748 : {
749 2 : ptr[0] = static_cast<float>(low);
750 2 : ptr[1] = static_cast<float>(high);
751 2 : }
752 :
753 2 : void Store2Val(unsigned char *ptr) const
754 : {
755 2 : ptr[0] = (unsigned char)(low + 0.5);
756 2 : ptr[1] = (unsigned char)(high + 0.5);
757 2 : }
758 :
759 2 : void Store2Val(unsigned short *ptr) const
760 : {
761 2 : ptr[0] = (GUInt16)(low + 0.5);
762 2 : ptr[1] = (GUInt16)(high + 0.5);
763 2 : }
764 :
765 8 : inline void StoreMask(unsigned char *ptr) const
766 : {
767 8 : memcpy(ptr, &low, 8);
768 8 : memcpy(ptr + 8, &high, 8);
769 8 : }
770 :
771 : inline operator double() const
772 : {
773 : return low;
774 : }
775 : };
776 :
777 : #endif /* defined(__x86_64) || defined(_M_X64) */
778 :
779 : #if defined(__AVX__) && !defined(USE_SSE2_EMULATION)
780 :
781 : #include <immintrin.h>
782 :
783 : class XMMReg4Double
784 : {
785 : public:
786 : __m256d ymm;
787 :
788 : XMMReg4Double() : ymm(_mm256_setzero_pd())
789 : {
790 : }
791 :
792 : XMMReg4Double(const XMMReg4Double &other) : ymm(other.ymm)
793 : {
794 : }
795 :
796 : static inline XMMReg4Double Zero()
797 : {
798 : XMMReg4Double reg;
799 : reg.Zeroize();
800 : return reg;
801 : }
802 :
803 : inline void Zeroize()
804 : {
805 : ymm = _mm256_setzero_pd();
806 : }
807 :
808 : static inline XMMReg4Double Load1ValHighAndLow(const double *ptr)
809 : {
810 : XMMReg4Double reg;
811 : reg.nsLoad1ValHighAndLow(ptr);
812 : return reg;
813 : }
814 :
815 : inline void nsLoad1ValHighAndLow(const double *ptr)
816 : {
817 : ymm = _mm256_set1_pd(*ptr);
818 : }
819 :
820 : static inline XMMReg4Double Load4Val(const unsigned char *ptr)
821 : {
822 : XMMReg4Double reg;
823 : reg.nsLoad4Val(ptr);
824 : return reg;
825 : }
826 :
827 : inline void nsLoad4Val(const unsigned char *ptr)
828 : {
829 : __m128i xmm_i = GDALCopyInt32ToXMM(ptr);
830 : xmm_i = _mm_cvtepu8_epi32(xmm_i);
831 : ymm = _mm256_cvtepi32_pd(xmm_i);
832 : }
833 :
834 : static inline XMMReg4Double Load4Val(const short *ptr)
835 : {
836 : XMMReg4Double reg;
837 : reg.nsLoad4Val(ptr);
838 : return reg;
839 : }
840 :
841 : inline void nsLoad4Val(const short *ptr)
842 : {
843 : __m128i xmm_i = GDALCopyInt64ToXMM(ptr);
844 : xmm_i = _mm_cvtepi16_epi32(xmm_i);
845 : ymm = _mm256_cvtepi32_pd(xmm_i);
846 : }
847 :
848 : static inline XMMReg4Double Load4Val(const unsigned short *ptr)
849 : {
850 : XMMReg4Double reg;
851 : reg.nsLoad4Val(ptr);
852 : return reg;
853 : }
854 :
855 : inline void nsLoad4Val(const unsigned short *ptr)
856 : {
857 : __m128i xmm_i = GDALCopyInt64ToXMM(ptr);
858 : xmm_i = _mm_cvtepu16_epi32(xmm_i);
859 : ymm = _mm256_cvtepi32_pd(
860 : xmm_i); // ok to use signed conversion since we are in the ushort
861 : // range, so cannot be interpreted as negative int32
862 : }
863 :
864 : static inline XMMReg4Double Load4Val(const double *ptr)
865 : {
866 : XMMReg4Double reg;
867 : reg.nsLoad4Val(ptr);
868 : return reg;
869 : }
870 :
871 : inline void nsLoad4Val(const double *ptr)
872 : {
873 : ymm = _mm256_loadu_pd(ptr);
874 : }
875 :
876 : static inline XMMReg4Double Load4ValAligned(const double *ptr)
877 : {
878 : XMMReg4Double reg;
879 : reg.nsLoad4ValAligned(ptr);
880 : return reg;
881 : }
882 :
883 : inline void nsLoad4ValAligned(const double *ptr)
884 : {
885 : ymm = _mm256_load_pd(ptr);
886 : }
887 :
888 : static inline XMMReg4Double Load4Val(const float *ptr)
889 : {
890 : XMMReg4Double reg;
891 : reg.nsLoad4Val(ptr);
892 : return reg;
893 : }
894 :
895 : inline void nsLoad4Val(const float *ptr)
896 : {
897 : ymm = _mm256_cvtps_pd(_mm_loadu_ps(ptr));
898 : }
899 :
900 : static inline XMMReg4Double Equals(const XMMReg4Double &expr1,
901 : const XMMReg4Double &expr2)
902 : {
903 : XMMReg4Double reg;
904 : reg.ymm = _mm256_cmp_pd(expr1.ymm, expr2.ymm, _CMP_EQ_OQ);
905 : return reg;
906 : }
907 :
908 : static inline XMMReg4Double NotEquals(const XMMReg4Double &expr1,
909 : const XMMReg4Double &expr2)
910 : {
911 : XMMReg4Double reg;
912 : reg.ymm = _mm256_cmp_pd(expr1.ymm, expr2.ymm, _CMP_NEQ_OQ);
913 : return reg;
914 : }
915 :
916 : static inline XMMReg4Double Greater(const XMMReg4Double &expr1,
917 : const XMMReg4Double &expr2)
918 : {
919 : XMMReg4Double reg;
920 : reg.ymm = _mm256_cmp_pd(expr1.ymm, expr2.ymm, _CMP_GT_OQ);
921 : return reg;
922 : }
923 :
924 : static inline XMMReg4Double And(const XMMReg4Double &expr1,
925 : const XMMReg4Double &expr2)
926 : {
927 : XMMReg4Double reg;
928 : reg.ymm = _mm256_and_pd(expr1.ymm, expr2.ymm);
929 : return reg;
930 : }
931 :
932 : static inline XMMReg4Double Ternary(const XMMReg4Double &cond,
933 : const XMMReg4Double &true_expr,
934 : const XMMReg4Double &false_expr)
935 : {
936 : XMMReg4Double reg;
937 : reg.ymm = _mm256_or_pd(_mm256_and_pd(cond.ymm, true_expr.ymm),
938 : _mm256_andnot_pd(cond.ymm, false_expr.ymm));
939 : return reg;
940 : }
941 :
942 : static inline XMMReg4Double Min(const XMMReg4Double &expr1,
943 : const XMMReg4Double &expr2)
944 : {
945 : XMMReg4Double reg;
946 : reg.ymm = _mm256_min_pd(expr1.ymm, expr2.ymm);
947 : return reg;
948 : }
949 :
950 : inline XMMReg4Double &operator=(const XMMReg4Double &other)
951 : {
952 : ymm = other.ymm;
953 : return *this;
954 : }
955 :
956 : inline XMMReg4Double &operator+=(const XMMReg4Double &other)
957 : {
958 : ymm = _mm256_add_pd(ymm, other.ymm);
959 : return *this;
960 : }
961 :
962 : inline XMMReg4Double &operator*=(const XMMReg4Double &other)
963 : {
964 : ymm = _mm256_mul_pd(ymm, other.ymm);
965 : return *this;
966 : }
967 :
968 : inline XMMReg4Double operator+(const XMMReg4Double &other) const
969 : {
970 : XMMReg4Double ret;
971 : ret.ymm = _mm256_add_pd(ymm, other.ymm);
972 : return ret;
973 : }
974 :
975 : inline XMMReg4Double operator-(const XMMReg4Double &other) const
976 : {
977 : XMMReg4Double ret;
978 : ret.ymm = _mm256_sub_pd(ymm, other.ymm);
979 : return ret;
980 : }
981 :
982 : inline XMMReg4Double operator*(const XMMReg4Double &other) const
983 : {
984 : XMMReg4Double ret;
985 : ret.ymm = _mm256_mul_pd(ymm, other.ymm);
986 : return ret;
987 : }
988 :
989 : inline XMMReg4Double operator/(const XMMReg4Double &other) const
990 : {
991 : XMMReg4Double ret;
992 : ret.ymm = _mm256_div_pd(ymm, other.ymm);
993 : return ret;
994 : }
995 :
996 : void AddToLow(const XMMReg2Double &other)
997 : {
998 : __m256d ymm2 = _mm256_setzero_pd();
999 : ymm2 = _mm256_insertf128_pd(ymm2, other.xmm, 0);
1000 : ymm = _mm256_add_pd(ymm, ymm2);
1001 : }
1002 :
1003 : inline double GetHorizSum() const
1004 : {
1005 : __m256d ymm_tmp1, ymm_tmp2;
1006 : ymm_tmp2 = _mm256_hadd_pd(ymm, ymm);
1007 : ymm_tmp1 = _mm256_permute2f128_pd(ymm_tmp2, ymm_tmp2, 1);
1008 : ymm_tmp1 = _mm256_add_pd(ymm_tmp1, ymm_tmp2);
1009 : return _mm_cvtsd_f64(_mm256_castpd256_pd128(ymm_tmp1));
1010 : }
1011 :
1012 : inline void Store4Val(unsigned char *ptr) const
1013 : {
1014 : __m128i xmm_i =
1015 : _mm256_cvttpd_epi32(_mm256_add_pd(ymm, _mm256_set1_pd(0.5)));
1016 : // xmm_i = _mm_packs_epi32(xmm_i, xmm_i); // Pack int32 to int16
1017 : // xmm_i = _mm_packus_epi16(xmm_i, xmm_i); // Pack int16 to uint8
1018 : xmm_i =
1019 : _mm_shuffle_epi8(xmm_i, _mm_cvtsi32_si128(0 | (4 << 8) | (8 << 16) |
1020 : (12 << 24))); // SSSE3
1021 : GDALCopyXMMToInt32(xmm_i, reinterpret_cast<GInt32 *>(ptr));
1022 : }
1023 :
1024 : inline void Store4Val(unsigned short *ptr) const
1025 : {
1026 : __m128i xmm_i =
1027 : _mm256_cvttpd_epi32(_mm256_add_pd(ymm, _mm256_set1_pd(0.5)));
1028 : xmm_i = _mm_packus_epi32(xmm_i, xmm_i); // Pack uint32 to uint16
1029 : GDALCopyXMMToInt64(xmm_i, reinterpret_cast<GInt64 *>(ptr));
1030 : }
1031 :
1032 : inline void Store4Val(float *ptr) const
1033 : {
1034 : _mm_storeu_ps(ptr, _mm256_cvtpd_ps(ymm));
1035 : }
1036 :
1037 : inline void Store4Val(double *ptr) const
1038 : {
1039 : _mm256_storeu_pd(ptr, ymm);
1040 : }
1041 :
1042 : inline void StoreMask(unsigned char *ptr) const
1043 : {
1044 : _mm256_storeu_si256(reinterpret_cast<__m256i *>(ptr),
1045 : _mm256_castpd_si256(ymm));
1046 : }
1047 : };
1048 :
1049 : #else
1050 :
1051 : class XMMReg4Double
1052 : {
1053 : public:
1054 : XMMReg2Double low, high;
1055 :
1056 : #if defined(__GNUC__)
1057 : #pragma GCC diagnostic push
1058 : #pragma GCC diagnostic ignored "-Weffc++"
1059 : #endif
1060 : /* coverity[uninit_member] */
1061 27 : XMMReg4Double() = default;
1062 : #if defined(__GNUC__)
1063 : #pragma GCC diagnostic pop
1064 : #endif
1065 :
1066 1315500 : XMMReg4Double(const XMMReg4Double &other) : low(other.low), high(other.high)
1067 : {
1068 1316450 : }
1069 :
1070 144307000 : static inline XMMReg4Double Zero()
1071 : {
1072 : XMMReg4Double reg;
1073 144307000 : reg.low.Zeroize();
1074 143714000 : reg.high.Zeroize();
1075 144041000 : return reg;
1076 : }
1077 :
1078 71190902 : static inline XMMReg4Double Load1ValHighAndLow(const double *ptr)
1079 : {
1080 1 : XMMReg4Double reg;
1081 71190902 : reg.low.nsLoad1ValHighAndLow(ptr);
1082 71297202 : reg.high = reg.low;
1083 71355202 : return reg;
1084 : }
1085 :
1086 180108002 : static inline XMMReg4Double Load4Val(const unsigned char *ptr)
1087 : {
1088 1 : XMMReg4Double reg;
1089 180108002 : XMMReg2Double::Load4Val(ptr, reg.low, reg.high);
1090 180654002 : return reg;
1091 : }
1092 :
1093 1013842 : static inline XMMReg4Double Load4Val(const short *ptr)
1094 : {
1095 1 : XMMReg4Double reg;
1096 1013842 : reg.low.nsLoad2Val(ptr);
1097 1013842 : reg.high.nsLoad2Val(ptr + 2);
1098 1013842 : return reg;
1099 : }
1100 :
1101 22352502 : static inline XMMReg4Double Load4Val(const unsigned short *ptr)
1102 : {
1103 1 : XMMReg4Double reg;
1104 22352502 : reg.low.nsLoad2Val(ptr);
1105 22384802 : reg.high.nsLoad2Val(ptr + 2);
1106 22372902 : return reg;
1107 : }
1108 :
1109 169785016 : static inline XMMReg4Double Load4Val(const double *ptr)
1110 : {
1111 8 : XMMReg4Double reg;
1112 169785016 : reg.low.nsLoad2Val(ptr);
1113 169982016 : reg.high.nsLoad2Val(ptr + 2);
1114 170886016 : return reg;
1115 : }
1116 :
1117 42894900 : static inline XMMReg4Double Load4ValAligned(const double *ptr)
1118 : {
1119 : XMMReg4Double reg;
1120 42894900 : reg.low.nsLoad2ValAligned(ptr);
1121 42870800 : reg.high.nsLoad2ValAligned(ptr + 2);
1122 42870700 : return reg;
1123 : }
1124 :
1125 37634 : static inline XMMReg4Double Load4Val(const float *ptr)
1126 : {
1127 1 : XMMReg4Double reg;
1128 37634 : XMMReg2Double::Load4Val(ptr, reg.low, reg.high);
1129 37634 : return reg;
1130 : }
1131 :
1132 2 : static inline XMMReg4Double Equals(const XMMReg4Double &expr1,
1133 : const XMMReg4Double &expr2)
1134 : {
1135 1 : XMMReg4Double reg;
1136 2 : reg.low = XMMReg2Double::Equals(expr1.low, expr2.low);
1137 2 : reg.high = XMMReg2Double::Equals(expr1.high, expr2.high);
1138 2 : return reg;
1139 : }
1140 :
1141 1313362 : static inline XMMReg4Double NotEquals(const XMMReg4Double &expr1,
1142 : const XMMReg4Double &expr2)
1143 : {
1144 1 : XMMReg4Double reg;
1145 1313362 : reg.low = XMMReg2Double::NotEquals(expr1.low, expr2.low);
1146 1321142 : reg.high = XMMReg2Double::NotEquals(expr1.high, expr2.high);
1147 1319112 : return reg;
1148 : }
1149 :
1150 6 : static inline XMMReg4Double Greater(const XMMReg4Double &expr1,
1151 : const XMMReg4Double &expr2)
1152 : {
1153 3 : XMMReg4Double reg;
1154 6 : reg.low = XMMReg2Double::Greater(expr1.low, expr2.low);
1155 6 : reg.high = XMMReg2Double::Greater(expr1.high, expr2.high);
1156 6 : return reg;
1157 : }
1158 :
1159 1317200 : static inline XMMReg4Double And(const XMMReg4Double &expr1,
1160 : const XMMReg4Double &expr2)
1161 : {
1162 : XMMReg4Double reg;
1163 1317200 : reg.low = XMMReg2Double::And(expr1.low, expr2.low);
1164 1318530 : reg.high = XMMReg2Double::And(expr1.high, expr2.high);
1165 1318940 : return reg;
1166 : }
1167 :
1168 2 : static inline XMMReg4Double Ternary(const XMMReg4Double &cond,
1169 : const XMMReg4Double &true_expr,
1170 : const XMMReg4Double &false_expr)
1171 : {
1172 1 : XMMReg4Double reg;
1173 : reg.low =
1174 2 : XMMReg2Double::Ternary(cond.low, true_expr.low, false_expr.low);
1175 : reg.high =
1176 2 : XMMReg2Double::Ternary(cond.high, true_expr.high, false_expr.high);
1177 2 : return reg;
1178 : }
1179 :
1180 4036432 : static inline XMMReg4Double Min(const XMMReg4Double &expr1,
1181 : const XMMReg4Double &expr2)
1182 : {
1183 1 : XMMReg4Double reg;
1184 4036432 : reg.low = XMMReg2Double::Min(expr1.low, expr2.low);
1185 4057702 : reg.high = XMMReg2Double::Min(expr1.high, expr2.high);
1186 4039612 : return reg;
1187 : }
1188 :
1189 44371308 : inline XMMReg4Double &operator=(const XMMReg4Double &other)
1190 : {
1191 44371308 : low = other.low;
1192 44391408 : high = other.high;
1193 44439608 : return *this;
1194 : }
1195 :
1196 306819002 : inline XMMReg4Double &operator+=(const XMMReg4Double &other)
1197 : {
1198 306819002 : low += other.low;
1199 306455002 : high += other.high;
1200 307384002 : return *this;
1201 : }
1202 :
1203 10510802 : inline XMMReg4Double &operator*=(const XMMReg4Double &other)
1204 : {
1205 10510802 : low *= other.low;
1206 10510802 : high *= other.high;
1207 10510802 : return *this;
1208 : }
1209 :
1210 8 : inline XMMReg4Double operator+(const XMMReg4Double &other) const
1211 : {
1212 4 : XMMReg4Double ret;
1213 8 : ret.low = low + other.low;
1214 8 : ret.high = high + other.high;
1215 8 : return ret;
1216 : }
1217 :
1218 2 : inline XMMReg4Double operator-(const XMMReg4Double &other) const
1219 : {
1220 1 : XMMReg4Double ret;
1221 2 : ret.low = low - other.low;
1222 2 : ret.high = high - other.high;
1223 2 : return ret;
1224 : }
1225 :
1226 332153002 : inline XMMReg4Double operator*(const XMMReg4Double &other) const
1227 : {
1228 1 : XMMReg4Double ret;
1229 332153002 : ret.low = low * other.low;
1230 332564002 : ret.high = high * other.high;
1231 330961002 : return ret;
1232 : }
1233 :
1234 1321702 : inline XMMReg4Double operator/(const XMMReg4Double &other) const
1235 : {
1236 1 : XMMReg4Double ret;
1237 1321702 : ret.low = low / other.low;
1238 1324542 : ret.high = high / other.high;
1239 1325022 : return ret;
1240 : }
1241 :
1242 571642 : void AddToLow(const XMMReg2Double &other)
1243 : {
1244 571642 : low += other;
1245 571642 : }
1246 :
1247 142845002 : inline double GetHorizSum() const
1248 : {
1249 142845002 : return (low + high).GetHorizSum();
1250 : }
1251 :
1252 1649682 : inline void Store4Val(unsigned char *ptr) const
1253 : {
1254 : #ifdef USE_SSE2_EMULATION
1255 1 : low.Store2Val(ptr);
1256 1 : high.Store2Val(ptr + 2);
1257 : #else
1258 3303282 : __m128i tmpLow = _mm_cvttpd_epi32(_mm_add_pd(
1259 1649681 : low.xmm,
1260 : _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
1261 3311322 : __m128i tmpHigh = _mm_cvttpd_epi32(_mm_add_pd(
1262 1653591 : high.xmm,
1263 : _mm_set1_pd(0.5))); /* Convert the 2 double values to 2 integers */
1264 4969263 : auto tmp = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(tmpLow),
1265 : _mm_castsi128_ps(tmpHigh),
1266 : _MM_SHUFFLE(1, 0, 1, 0)));
1267 1655611 : tmp = _mm_packs_epi32(tmp, tmp);
1268 1662481 : tmp = _mm_packus_epi16(tmp, tmp);
1269 1662481 : GDALCopyXMMToInt32(tmp, reinterpret_cast<GInt32 *>(ptr));
1270 : #endif
1271 1647752 : }
1272 :
1273 2480892 : inline void Store4Val(unsigned short *ptr) const
1274 : {
1275 : #if 1
1276 2480892 : low.Store2Val(ptr);
1277 2480092 : high.Store2Val(ptr + 2);
1278 : #else
1279 : __m128i xmm0 = _mm_cvtpd_epi32(low.xmm);
1280 : __m128i xmm1 = _mm_cvtpd_epi32(high.xmm);
1281 : xmm0 = _mm_or_si128(xmm0, _mm_slli_si128(xmm1, 8));
1282 : #if __SSE4_1__
1283 : xmm0 = _mm_packus_epi32(xmm0, xmm0); // Pack uint32 to uint16
1284 : #else
1285 : xmm0 = _mm_add_epi32(xmm0, _mm_set1_epi32(-32768));
1286 : xmm0 = _mm_packs_epi32(xmm0, xmm0);
1287 : xmm0 = _mm_sub_epi16(xmm0, _mm_set1_epi16(-32768));
1288 : #endif
1289 : GDALCopyXMMToInt64(xmm0, (GInt64 *)ptr);
1290 : #endif
1291 2479402 : }
1292 :
1293 37146302 : inline void Store4Val(float *ptr) const
1294 : {
1295 37146302 : low.Store2Val(ptr);
1296 37187502 : high.Store2Val(ptr + 2);
1297 37179502 : }
1298 :
1299 32 : inline void Store4Val(double *ptr) const
1300 : {
1301 32 : low.Store2Val(ptr);
1302 32 : high.Store2Val(ptr + 2);
1303 32 : }
1304 :
1305 8 : inline void StoreMask(unsigned char *ptr) const
1306 : {
1307 8 : low.StoreMask(ptr);
1308 8 : high.StoreMask(ptr + 16);
1309 8 : }
1310 : };
1311 :
1312 : #endif
1313 :
1314 : #endif /* #ifndef DOXYGEN_SKIP */
1315 :
1316 : #endif /* GDALSSE_PRIV_H_INCLUDED */
|