1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2018 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qendian.h"
6
7#include "qalgorithms.h"
8#include <private/qsimd_p.h>
9
10QT_BEGIN_NAMESPACE
11
12/*!
13 \headerfile <QtEndian>
14 \inmodule QtCore
15 \title Endian Conversion Functions
16 \ingroup funclists
17 \brief The <QtEndian> header provides functions to convert between
18 little and big endian representations of numbers.
19*/
20
21/*!
22 \fn template <typename T> T qFromUnaligned(const void *ptr)
23 \internal
24 \since 5.5
25
26 Loads a \c{T} from address \a ptr, which may be misaligned.
27
28 Use of this function avoids the undefined behavior that the C++ standard
29 otherwise attributes to unaligned loads.
30*/
31
32/*!
33 \fn template <typename T> void qToUnaligned(const T t, void *ptr)
34 \internal
35 \since 4.5
36
37 Stores \a t to address \a ptr, which may be misaligned.
38
39 Use of this function avoids the undefined behavior that the C++ standard
40 otherwise attributes to unaligned stores.
41*/
42
43
44/*!
45 \fn template <typename T> T qFromBigEndian(const void *src)
46 \since 4.3
47 \relates <QtEndian>
48
49 Reads a big-endian number from memory location \a src and returns the number in the
50 host byte order representation.
51 On CPU architectures where the host byte order is little-endian (such as x86) this
52 will swap the byte order; otherwise it will just read from \a src.
53
54 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
55 quint64, or qint64. Other types of integers, e.g., qlong, are not
56 applicable.
57
58 \note Since Qt 5.7, the type of the \a src parameter is a void pointer.
59
60 There are no data alignment constraints for \a src.
61
62 \sa qFromLittleEndian()
63 \sa qToBigEndian()
64 \sa qToLittleEndian()
65*/
66/*!
67 \fn template <typename T> T qFromBigEndian(T src)
68 \since 4.3
69 \relates <QtEndian>
70 \overload
71
72 Converts \a src from big-endian byte order and returns the number in host byte order
73 representation of that number.
74 On CPU architectures where the host byte order is little-endian (such as x86) this
75 will return \a src with the byte order swapped; otherwise it will return \a src
76 unmodified.
77*/
78/*!
79 \fn template <typename T> T qFromBigEndian(const void *src, qsizetype count, void *dest)
80 \since 5.12
81 \relates <QtEndian>
82
83 Reads \a count big-endian numbers from memory location \a src and stores
84 them in the host byte order representation at \a dest. On CPU architectures
85 where the host byte order is little-endian (such as x86) this will swap the
86 byte order; otherwise it will just perform a \c memcpy from \a src to \a
87 dest.
88
89 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
90 quint64, or qint64. Other types of integers, e.g., qlong, are not
91 applicable.
92
93 There are no data alignment constraints for \a src. However, \a dest is
94 expected to be naturally aligned for type \c{T}.
95
96 If \a src and \a dest can be the same pointer, this function will perform
97 an in-place swap (if necessary). If they are not the same, the memory
98 regions must not overlap.
99
100 \sa qFromLittleEndian()
101 \sa qToBigEndian()
102 \sa qToLittleEndian()
103*/
104/*!
105 \fn template <typename T> inline T qFromLittleEndian(const void *src)
106 \since 4.3
107 \relates <QtEndian>
108
109 Reads a little-endian number from memory location \a src and returns the number in
110 the host byte order representation.
111 On CPU architectures where the host byte order is big-endian (such as PowerPC) this
112 will swap the byte order; otherwise it will just read from \a src.
113
114 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
115 quint64, or qint64. Other types of integers, e.g., qlong, are not
116 applicable.
117
118 \note Since Qt 5.7, the type of the \a src parameter is a void pointer.
119
120 There are no data alignment constraints for \a src.
121
122 \sa qFromBigEndian()
123 \sa qToBigEndian()
124 \sa qToLittleEndian()
125*/
126/*!
127 \fn template <typename T> inline T qFromLittleEndian(T src)
128 \since 4.3
129 \relates <QtEndian>
130 \overload
131
132 Converts \a src from little-endian byte order and returns the number in host byte
133 order representation of that number.
134 On CPU architectures where the host byte order is big-endian (such as PowerPC) this
135 will return \a src with the byte order swapped; otherwise it will return \a src
136 unmodified.
137*/
138/*!
139 \fn template <typename T> inline T qFromLittleEndian(const void *src, qsizetype count, void *dest)
140 \since 5.12
141 \relates <QtEndian>
142
143 Reads \a count little-endian numbers from memory location \a src and stores
144 them in the host byte order representation at \a dest. On CPU architectures
145 where the host byte order is big-endian (such as PowerPC) this will swap the
146 byte order; otherwise it will just perform a \c memcpy from \a src to \a
147 dest.
148
149 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
150 quint64, or qint64. Other types of integers, e.g., qlong, are not
151 applicable.
152
153 There are no data alignment constraints for \a src. However, \a dest is
154 expected to be naturally aligned for type \c{T}.
155
156 If \a src and \a dest can be the same pointer, this function will perform
157 an in-place swap (if necessary). If they are not the same, the memory
158 regions must not overlap.
159
160 \sa qToBigEndian()
161 \sa qToLittleEndian()
162*/
163/*!
164 \fn template <typename T> void qToBigEndian(T src, void *dest)
165 \since 4.3
166 \relates <QtEndian>
167
168 Writes the number \a src with template type \c{T} to the memory location at \a dest
169 in big-endian byte order.
170
171 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
172 quint64, or qint64. Other types of integers, e.g., qlong, are not
173 applicable.
174
175 There are no data alignment constraints for \a dest.
176
177 \note Since Qt 5.7, the type of the \a dest parameter is a void pointer.
178
179 \sa qFromBigEndian()
180 \sa qFromLittleEndian()
181 \sa qToLittleEndian()
182*/
183/*!
184 \fn template <typename T> T qToBigEndian(T src)
185 \since 4.3
186 \relates <QtEndian>
187 \overload
188
189 Converts \a src from host byte order and returns the number in big-endian byte order
190 representation of that number.
191 On CPU architectures where the host byte order is little-endian (such as x86) this
192 will return \a src with the byte order swapped; otherwise it will return \a src
193 unmodified.
194*/
195/*!
196 \fn template <typename T> T qToBigEndian(const void *src, qsizetype count, void *dest)
197 \since 5.12
198 \relates <QtEndian>
199
200 Reads \a count numbers from memory location \a src in the host byte order
201 and stores them in big-endian representation at \a dest. On CPU
202 architectures where the host byte order is little-endian (such as x86) this
203 will swap the byte order; otherwise it will just perform a \c memcpy from
204 \a src to \a dest.
205
206 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
207 quint64, or qint64. Other types of integers, e.g., qlong, are not
208 applicable.
209
210 There are no data alignment constraints for \a dest. However, \a src is
211 expected to be naturally aligned for type \c{T}.
212
213 If \a src and \a dest can be the same pointer, this function will perform
214 an in-place swap (if necessary). If they are not the same, the memory
215 regions must not overlap.
216
217 \sa qFromLittleEndian()
218 \sa qToBigEndian()
219 \sa qToLittleEndian()
220*/
221/*!
222 \fn template <typename T> void qToLittleEndian(T src, void *dest)
223 \since 4.3
224 \relates <QtEndian>
225
226 Writes the number \a src with template type \c{T} to the memory location at \a dest
227 in little-endian byte order.
228
229 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
230 quint64, or qint64. Other types of integers, e.g., qlong, are not
231 applicable.
232
233 There are no data alignment constraints for \a dest.
234
235 \note Since Qt 5.7, the type of the \a dest parameter is a void pointer.
236
237 \sa qFromBigEndian()
238 \sa qFromLittleEndian()
239 \sa qToBigEndian()
240*/
241/*!
242 \fn template <typename T> T qToLittleEndian(T src)
243 \since 4.3
244 \relates <QtEndian>
245 \overload
246
247 Converts \a src from host byte order and returns the number in little-endian byte
248 order representation of that number.
249 On CPU architectures where the host byte order is big-endian (such as PowerPC) this
250 will return \a src with the byte order swapped; otherwise it will return \a src
251 unmodified.
252*/
253/*!
254 \fn template <typename T> T qToLittleEndian(const void *src, qsizetype count, void *dest)
255 \since 5.12
256 \relates <QtEndian>
257
258 Reads \a count numbers from memory location \a src in the host byte order
259 and stores them in little-endian representation at \a dest. On CPU
260 architectures where the host byte order is big-endian (such as PowerPC)
261 this will swap the byte order; otherwise it will just perform a \c memcpy
262 from \a src to \a dest.
263
264 \note Template type \c{T} can either be a quint16, qint16, quint32, qint32,
265 quint64, or qint64. Other types of integers, e.g., qlong, are not
266 applicable.
267
268 There are no data alignment constraints for \a dest. However, \a src is
269 expected to be naturally aligned for type \c{T}.
270
271 If \a src and \a dest can be the same pointer, this function will perform
272 an in-place swap (if necessary). If they are not the same, the memory
273 regions must not overlap.
274
275 \sa qFromLittleEndian()
276 \sa qToBigEndian()
277 \sa qToLittleEndian()
278*/
279
280/*!
281 \class QLEInteger
282 \inmodule QtCore
283 \brief The QLEInteger class provides platform-independent little-endian integers.
284 \since 5.10
285
286 The template parameter \c T must be a C++ integer type:
287 \list
288 \li 8-bit: char, signed char, unsigned char, qint8, quint8
289 \li 16-bit: short, unsigned short, qint16, quint16, char16_t
290 \li 32-bit: int, unsigned int, qint32, quint32, char32_t
291 \li 64-bit: long long, unsigned long long, qint64, quint64
292 \li platform-specific size: long, unsigned long
293 \li pointer size: qintptr, quintptr, qptrdiff
294 \endlist
295
296 \note Using this class may be slower than using native integers, so only use it when
297 an exact endianness is needed.
298*/
299
300/*! \fn template <typename T> QLEInteger<T>::QLEInteger(T value)
301
302 Constructs a QLEInteger with the given \a value.
303*/
304
305/*! \fn template <typename T> QLEInteger &QLEInteger<T>::operator=(T i)
306
307 Assigns \a i to this QLEInteger and returns a reference to
308 this QLEInteger.
309*/
310
311/*!
312 \fn template <typename T> QLEInteger<T>::operator T() const
313
314 Returns the value of this QLEInteger as a native integer.
315*/
316
317/*!
318 \fn template <typename T> bool QLEInteger<T>::operator==(QLEInteger other) const
319
320 Returns \c true if the value of this QLEInteger is equal to the value of \a other.
321*/
322
323/*!
324 \fn template <typename T> bool QLEInteger<T>::operator!=(QLEInteger other) const
325
326 Returns \c true if the value of this QLEInteger is not equal to the value of \a other.
327*/
328
329/*!
330 \fn template <typename T> QLEInteger &QLEInteger<T>::operator+=(T i)
331
332 Adds \a i to this QLEInteger and returns a reference to
333 this object.
334*/
335
336/*!
337 \fn template <typename T> QLEInteger &QLEInteger<T>::operator-=(T i)
338
339 Subtracts \a i from this QLEInteger and returns a reference to
340 this object.
341*/
342
343/*!
344 \fn template <typename T> QLEInteger &QLEInteger<T>::operator*=(T i)
345
346 Multiplies \a i with this QLEInteger and returns a reference to
347 this object.
348*/
349
350/*!
351 \fn template <typename T> QLEInteger &QLEInteger<T>::operator/=(T i)
352
353 Divides this QLEInteger with \a i and returns a reference to
354 this object.
355*/
356
357/*!
358 \fn template <typename T> QLEInteger &QLEInteger<T>::operator%=(T i)
359
360 Sets this QLEInteger to the remainder of a division by \a i and
361 returns a reference to this object.
362*/
363
364/*!
365 \fn template <typename T> QLEInteger &QLEInteger<T>::operator>>=(T i)
366
367 Performs a left-shift by \a i on this QLEInteger and returns a
368 reference to this object.
369*/
370
371/*!
372 \fn template <typename T> QLEInteger &QLEInteger<T>::operator<<=(T i)
373
374 Performs a right-shift by \a i on this QLEInteger and returns a
375 reference to this object.
376*/
377
378/*!
379 \fn template <typename T> QLEInteger &QLEInteger<T>::operator|=(T i)
380
381 Performs a bitwise OR with \a i onto this QLEInteger and returns a reference to
382 this object.
383*/
384
385/*!
386 \fn template <typename T> QLEInteger &QLEInteger<T>::operator&=(T i)
387
388 Performs a bitwise AND with \a i onto this QLEInteger and returns a reference to
389 this object.
390*/
391
392/*!
393 \fn template <typename T> QLEInteger &QLEInteger<T>::operator^=(T i)
394
395 Performs a bitwise XOR with \a i onto this QLEInteger and returns a reference to
396 this object.
397*/
398
399/*!
400 \fn template <typename T> QLEInteger &QLEInteger<T>::operator++()
401
402 Performs a prefix \c{++} (increment) on this QLEInteger and returns a reference to
403 this object.
404*/
405
406/*!
407 \fn template <typename T> QLEInteger QLEInteger<T>::operator++(int)
408
409 Performs a postfix \c{++} (increment) on this QLEInteger and returns a reference to
410 this object.
411*/
412
413/*!
414 \fn template <typename T> QLEInteger &QLEInteger<T>::operator--()
415
416 Performs a prefix \c{--} (decrement) on this QLEInteger and returns a reference to
417 this object.
418*/
419
420/*!
421 \fn template <typename T> QLEInteger QLEInteger<T>::operator--(int)
422
423 Performs a postfix \c{--} (decrement) on this QLEInteger and returns a reference to
424 this object.
425*/
426
427/*!
428 \fn template <typename T> QLEInteger QLEInteger<T>::max()
429
430 Returns the maximum (finite) value representable by the numeric type T.
431*/
432
433/*!
434 \fn template <typename T> QLEInteger QLEInteger<T>::min()
435
436 Returns the minimum (finite) value representable by the numeric type T.
437*/
438
439/*!
440 \class QBEInteger
441 \inmodule QtCore
442 \brief The QBEInteger class provides platform-independent big-endian integers.
443 \since 5.10
444
445 The template parameter \c T must be a C++ integer type:
446 \list
447 \li 8-bit: char, signed char, unsigned char, qint8, quint8
448 \li 16-bit: short, unsigned short, qint16, quint16, char16_t (C++11)
449 \li 32-bit: int, unsigned int, qint32, quint32, char32_t (C++11)
450 \li 64-bit: long long, unsigned long long, qint64, quint64
451 \li platform-specific size: long, unsigned long
452 \li pointer size: qintptr, quintptr, qptrdiff
453 \endlist
454
455 \note Using this class may be slower than using native integers, so only use it when
456 an exact endianness is needed.
457*/
458
459/*! \fn template <typename T> QBEInteger<T>::QBEInteger(T value)
460
461 Constructs a QBEInteger with the given \a value.
462*/
463
464/*! \fn template <typename T> QBEInteger &QBEInteger<T>::operator=(T i)
465
466 Assigns \a i to this QBEInteger and returns a reference to
467 this QBEInteger.
468*/
469
470/*!
471 \fn template <typename T> QBEInteger<T>::operator T() const
472
473 Returns the value of this QBEInteger as a native integer.
474*/
475
476/*!
477 \fn template <typename T> bool QBEInteger<T>::operator==(QBEInteger other) const
478
479 Returns \c true if the value of this QBEInteger is equal to the value of \a other.
480*/
481
482/*!
483 \fn template <typename T> bool QBEInteger<T>::operator!=(QBEInteger other) const
484
485 Returns \c true if the value of this QBEInteger is not equal to the value of \a other.
486*/
487
488/*!
489 \fn template <typename T> QBEInteger &QBEInteger<T>::operator+=(T i)
490
491 Adds \a i to this QBEInteger and returns a reference to
492 this object.
493*/
494
495/*!
496 \fn template <typename T> QBEInteger &QBEInteger<T>::operator-=(T i)
497
498 Subtracts \a i from this QBEInteger and returns a reference to
499 this object.
500*/
501
502/*!
503 \fn template <typename T> QBEInteger &QBEInteger<T>::operator*=(T i)
504
505 Multiplies \a i with this QBEInteger and returns a reference to
506 this object.
507*/
508
509/*!
510 \fn template <typename T> QBEInteger &QBEInteger<T>::operator/=(T i)
511
512 Divides this QBEInteger with \a i and returns a reference to
513 this object.
514*/
515
516/*!
517 \fn template <typename T> QBEInteger &QBEInteger<T>::operator%=(T i)
518
519 Sets this QBEInteger to the remainder of a division by \a i and
520 returns a reference to this object.
521*/
522
523/*!
524 \fn template <typename T> QBEInteger &QBEInteger<T>::operator>>=(T i)
525
526 Performs a left-shift by \a i on this QBEInteger and returns a
527 reference to this object.
528*/
529
530/*!
531 \fn template <typename T> QBEInteger &QBEInteger<T>::operator<<=(T i)
532
533 Performs a right-shift by \a i on this QBEInteger and returns a
534 reference to this object.
535*/
536
537/*!
538 \fn template <typename T> QBEInteger &QBEInteger<T>::operator|=(T i)
539
540 Performs a bitwise OR with \a i onto this QBEInteger and returns a reference to
541 this object.
542*/
543
544/*!
545 \fn template <typename T> QBEInteger &QBEInteger<T>::operator&=(T i)
546
547 Performs a bitwise AND with \a i onto this QBEInteger and returns a reference to
548 this object.
549*/
550
551/*!
552 \fn template <typename T> QBEInteger &QBEInteger<T>::operator^=(T i)
553
554 Performs a bitwise XOR with \a i onto this QBEInteger and returns a reference to
555 this object.
556*/
557
558/*!
559 \fn template <typename T> QBEInteger &QBEInteger<T>::operator++()
560
561 Performs a prefix \c{++} (increment) on this QBEInteger and returns a reference to
562 this object.
563*/
564
565/*!
566 \fn template <typename T> QBEInteger QBEInteger<T>::operator++(int)
567
568 Performs a postfix \c{++} (increment) on this QBEInteger and returns a reference to
569 this object.
570*/
571
572/*!
573 \fn template <typename T> QBEInteger &QBEInteger<T>::operator--()
574
575 Performs a prefix \c{--} (decrement) on this QBEInteger and returns a reference to
576 this object.
577*/
578
579/*!
580 \fn template <typename T> QBEInteger QBEInteger<T>::operator--(int)
581
582 Performs a postfix \c{--} (decrement) on this QBEInteger and returns a reference to
583 this object.
584*/
585
586/*!
587 \fn template <typename T> QBEInteger QBEInteger<T>::max()
588
589 Returns the maximum (finite) value representable by the numeric type T.
590*/
591
592/*!
593 \fn template <typename T> QBEInteger QBEInteger<T>::min()
594
595 Returns the minimum (finite) value representable by the numeric type T.
596*/
597
598/*!
599 \typedef quint16_le
600 \relates <QtEndian>
601 \since 5.10
602
603 Typedef for QLEInteger<quint16>. This type is guaranteed to be stored in memory as
604 a 16-bit little-endian unsigned integer on all platforms supported by Qt.
605
606 \sa quint16
607*/
608
609/*!
610 \typedef quint32_le
611 \relates <QtEndian>
612 \since 5.10
613
614 Typedef for QLEInteger<quint32>. This type is guaranteed to be stored in memory as
615 a 32-bit little-endian unsigned integer on all platforms supported by Qt.
616
617 \sa quint32
618*/
619
620/*!
621 \typedef quint64_le
622 \relates <QtEndian>
623 \since 5.10
624
625 Typedef for QLEInteger<quint64>. This type is guaranteed to be stored in memory as
626 a 64-bit little-endian unsigned integer on all platforms supported by Qt.
627
628 \sa quint64
629*/
630
631/*!
632 \typedef quint16_be
633 \relates <QtEndian>
634 \since 5.10
635
636 Typedef for QBEInteger<quint16>. This type is guaranteed to be stored in memory as
637 a 16-bit big-endian unsigned integer on all platforms supported by Qt.
638
639 \sa quint16
640*/
641
642/*!
643 \typedef quint32_be
644 \relates <QtEndian>
645 \since 5.10
646
647 Typedef for QBEInteger<quint32>. This type is guaranteed to be stored in memory as
648 a 32-bit big-endian unsigned integer on all platforms supported by Qt.
649
650 \sa quint32
651*/
652
653/*!
654 \typedef quint64_be
655 \relates <QtEndian>
656 \since 5.10
657
658 Typedef for QBEInteger<quint64>. This type is guaranteed to be stored in memory as
659 a 64-bit big-endian unsigned integer on all platforms supported by Qt.
660
661 \sa quint64
662*/
663
664/*!
665 \typedef qint16_le
666 \relates <QtEndian>
667 \since 5.10
668
669 Typedef for QLEInteger<qint16>. This type is guaranteed to be stored in memory as
670 a 16-bit little-endian signed integer on all platforms supported by Qt.
671
672 \sa qint16
673*/
674
675/*!
676 \typedef qint32_le
677 \relates <QtEndian>
678 \since 5.10
679
680 Typedef for QLEInteger<qint32>. This type is guaranteed to be stored in memory as
681 a 32-bit little-endian signed integer on all platforms supported by Qt.
682
683 \sa qint32
684*/
685
686/*!
687 \typedef qint64_le
688 \relates <QtEndian>
689 \since 5.10
690
691 Typedef for QLEInteger<qint64>. This type is guaranteed to be stored in memory as
692 a 64-bit little-endian signed integer on all platforms supported by Qt.
693
694 \sa qint64
695*/
696
697/*!
698 \typedef qint16_be
699 \relates <QtEndian>
700 \since 5.10
701
702 Typedef for QBEInteger<qint16>. This type is guaranteed to be stored in memory as
703 a 16-bit big-endian signed integer on all platforms supported by Qt.
704
705 \sa qint16
706*/
707
708/*!
709 \typedef qint32_be
710 \relates <QtEndian>
711 \since 5.10
712
713 Typedef for QBEInteger<qint32>. This type is guaranteed to be stored in memory as
714 a 32-bit big-endian signed integer on all platforms supported by Qt.
715
716 \sa qint32
717*/
718
719/*!
720 \typedef qint64_be
721 \relates <QtEndian>
722 \since 5.10
723
724 Typedef for QBEInteger<qint64>. This type is guaranteed to be stored in memory as
725 a 64-bit big-endian signed integer on all platforms supported by Qt.
726
727 \sa qint64
728*/
729
730#if defined(__SSSE3__)
731using ShuffleMask = uchar[16];
732alignas(16) static const ShuffleMask shuffleMasks[3] = {
733 // 16-bit
734 {1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14},
735 // 32-bit
736 {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
737 // 64-bit
738 {7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8}
739};
740
741static size_t sseSwapLoop(const uchar *src, size_t bytes, uchar *dst,
742 const __m128i *shuffleMaskPtr) noexcept
743{
744 size_t i = 0;
745 const __m128i shuffleMask = _mm_load_si128(shuffleMaskPtr);
746
747# ifdef __AVX2__
748 const __m256i shuffleMask256 = _mm256_inserti128_si256(_mm256_castsi128_si256(shuffleMask), shuffleMask, 1);
749 for ( ; i + sizeof(__m256i) <= bytes; i += sizeof(__m256i)) {
750 __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(src + i));
751 data = _mm256_shuffle_epi8(data, shuffleMask256);
752 _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst + i), data);
753 }
754# else
755 for ( ; i + 2 * sizeof(__m128i) <= bytes; i += 2 * sizeof(__m128i)) {
756 __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i));
757 __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i) + 1);
758 data1 = _mm_shuffle_epi8(data1, shuffleMask);
759 data2 = _mm_shuffle_epi8(data2, shuffleMask);
760 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data1);
761 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i) + 1, data2);
762 }
763# endif
764
765 if (i + sizeof(__m128i) <= bytes) {
766 __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(src + i));
767 data = _mm_shuffle_epi8(data, shuffleMask);
768 _mm_storeu_si128(reinterpret_cast<__m128i *>(dst + i), data);
769 i += sizeof(__m128i);
770 }
771
772 return i;
773}
774
775template <typename T> static Q_ALWAYS_INLINE
776size_t simdSwapLoop(const uchar *src, size_t bytes, uchar *dst) noexcept
777{
778 auto shuffleMaskPtr = reinterpret_cast<const __m128i *>(shuffleMasks[0]);
779 shuffleMaskPtr += qCountTrailingZeroBits(sizeof(T)) - 1;
780 size_t i = sseSwapLoop(src, bytes, dst, shuffleMaskPtr);
781
782 // epilogue
783 for (size_t _i = 0; i < bytes && _i < sizeof(__m128i); i += sizeof(T), _i += sizeof(T))
784 qbswap(qFromUnaligned<T>(src + i), dst + i);
785
786 // return the total, so the bswapLoop below does nothing
787 return bytes;
788}
789#elif defined(__SSE2__)
790template <typename T> static
791size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept
792{
793 // no generic version: we can't do 32- and 64-bit swaps easily,
794 // so we won't try
795 return 0;
796}
797
798template <> size_t simdSwapLoop<quint16>(const uchar *src, size_t bytes, uchar *dst) noexcept
799{
800 auto swapEndian = [](__m128i &data) {
801 __m128i lows = _mm_srli_epi16(a: data, count: 8);
802 __m128i highs = _mm_slli_epi16(a: data, count: 8);
803 data = _mm_xor_si128(a: lows, b: highs);
804 };
805
806 size_t i = 0;
807 for ( ; i + 2 * sizeof(__m128i) <= bytes; i += 2 * sizeof(__m128i)) {
808 __m128i data1 = _mm_loadu_si128(p: reinterpret_cast<const __m128i *>(src + i));
809 __m128i data2 = _mm_loadu_si128(p: reinterpret_cast<const __m128i *>(src + i) + 1);
810 swapEndian(data1);
811 swapEndian(data2);
812 _mm_storeu_si128(p: reinterpret_cast<__m128i *>(dst + i), b: data1);
813 _mm_storeu_si128(p: reinterpret_cast<__m128i *>(dst + i) + 1, b: data2);
814 }
815
816 if (i + sizeof(__m128i) <= bytes) {
817 __m128i data = _mm_loadu_si128(p: reinterpret_cast<const __m128i *>(src + i));
818 swapEndian(data);
819 _mm_storeu_si128(p: reinterpret_cast<__m128i *>(dst + i), b: data);
820 i += sizeof(__m128i);
821 }
822
823 // epilogue
824 for (size_t _i = 0 ; i < bytes && _i < sizeof(__m128i); i += sizeof(quint16), _i += sizeof(quint16))
825 qbswap(src: qFromUnaligned<quint16>(src: src + i), dest: dst + i);
826
827 // return the total, so the bswapLoop below does nothing
828 return bytes;
829}
830#else
831template <typename T> static Q_ALWAYS_INLINE
832size_t simdSwapLoop(const uchar *, size_t, uchar *) noexcept
833{
834 return 0;
835}
836#endif
837
838template <typename T> static Q_ALWAYS_INLINE
839void *bswapLoop(const uchar *src, size_t n, uchar *dst) noexcept
840{
841 // Buffers cannot partially overlap: either they're identical or totally
842 // disjoint (note: they can be adjacent).
843 if (src != dst) {
844 quintptr s = quintptr(src);
845 quintptr d = quintptr(dst);
846 if (s < d)
847 Q_ASSERT(s + n <= d);
848 else
849 Q_ASSERT(d + n <= s);
850 }
851
852 size_t i = simdSwapLoop<T>(src, n, dst);
853
854 for (; i < n; i += sizeof(T))
855 qbswap(qFromUnaligned<T>(src + i), dst + i);
856 return dst + i;
857}
858
859template<>
860void *qbswap<2>(const void *source, qsizetype n, void *dest) noexcept
861{
862 const uchar *src = reinterpret_cast<const uchar *>(source);
863 uchar *dst = reinterpret_cast<uchar *>(dest);
864
865 return bswapLoop<quint16>(src, n: n << 1, dst);
866}
867
868template<>
869void *qbswap<4>(const void *source, qsizetype n, void *dest) noexcept
870{
871 const uchar *src = reinterpret_cast<const uchar *>(source);
872 uchar *dst = reinterpret_cast<uchar *>(dest);
873
874 return bswapLoop<quint32>(src, n: n << 2, dst);
875}
876
877template<>
878void *qbswap<8>(const void *source, qsizetype n, void *dest) noexcept
879{
880 const uchar *src = reinterpret_cast<const uchar *>(source);
881 uchar *dst = reinterpret_cast<uchar *>(dest);
882
883 return bswapLoop<quint64>(src, n: n << 3, dst);
884}
885
886QT_END_NAMESPACE
887

source code of qtbase/src/corelib/global/qendian.cpp