1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /**
23  * # CategoryEndian
24  *
25  * Functions for reading and writing endian-specific values
26  */
27 
28 #ifndef SDL_endian_h_
29 #define SDL_endian_h_
30 
31 #include "SDL_stdinc.h"
32 
33 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
34 /* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version,
35    so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */
36 #ifdef __clang__
37 #ifndef __PRFCHWINTRIN_H
38 #define __PRFCHWINTRIN_H
39 static __inline__ void __attribute__((__always_inline__, __nodebug__))
_m_prefetch(void * __P)40 _m_prefetch(void *__P)
41 {
42   __builtin_prefetch(__P, 0, 3 /* _MM_HINT_T0 */);
43 }
44 #endif /* __PRFCHWINTRIN_H */
45 #endif /* __clang__ */
46 
47 #include <intrin.h>
48 #endif
49 
50 /**
51  *  \name The two types of endianness
52  */
53 /* @{ */
54 #define SDL_LIL_ENDIAN  1234
55 #define SDL_BIG_ENDIAN  4321
56 /* @} */
57 
58 #ifndef SDL_BYTEORDER           /* Not defined in SDL_config.h? */
59 #ifdef __linux__
60 #include <endian.h>
61 #define SDL_BYTEORDER  __BYTE_ORDER
62 #elif defined(__sun) && defined(__SVR4)  /* Solaris */
63 #include <sys/byteorder.h>
64 #if defined(_LITTLE_ENDIAN)
65 #define SDL_BYTEORDER   SDL_LIL_ENDIAN
66 #elif defined(_BIG_ENDIAN)
67 #define SDL_BYTEORDER   SDL_BIG_ENDIAN
68 #else
69 #error Unsupported endianness
70 #endif
71 #elif defined(__OpenBSD__) || defined(__DragonFly__)
72 #include <endian.h>
73 #define SDL_BYTEORDER  BYTE_ORDER
74 #elif defined(__FreeBSD__) || defined(__NetBSD__)
75 #include <sys/endian.h>
76 #define SDL_BYTEORDER  BYTE_ORDER
77 /* predefs from newer gcc and clang versions: */
78 #elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__)
79 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
80 #define SDL_BYTEORDER   SDL_LIL_ENDIAN
81 #elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
82 #define SDL_BYTEORDER   SDL_BIG_ENDIAN
83 #else
84 #error Unsupported endianness
85 #endif /**/
86 #else
87 #if defined(__hppa__) || \
88     defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
89     (defined(__MIPS__) && defined(__MIPSEB__)) || \
90     defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \
91     defined(__sparc__) || defined(__sparc)
92 #define SDL_BYTEORDER   SDL_BIG_ENDIAN
93 #else
94 #define SDL_BYTEORDER   SDL_LIL_ENDIAN
95 #endif
96 #endif /* __linux__ */
97 #endif /* !SDL_BYTEORDER */
98 
99 #ifndef SDL_FLOATWORDORDER           /* Not defined in SDL_config.h? */
100 /* predefs from newer gcc versions: */
101 #if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
102 #if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
103 #define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
104 #elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
105 #define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
106 #else
107 #error Unsupported endianness
108 #endif /**/
109 #elif defined(__MAVERICK__)
110 /* For Maverick, float words are always little-endian. */
111 #define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
112 #elif (defined(__arm__) || defined(__thumb__)) && !defined(__VFP_FP__) && !defined(__ARM_EABI__)
113 /* For FPA, float words are always big-endian. */
114 #define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
115 #else
116 /* By default, assume that floats words follow the memory system mode. */
117 #define SDL_FLOATWORDORDER   SDL_BYTEORDER
118 #endif /* __FLOAT_WORD_ORDER__ */
119 #endif /* !SDL_FLOATWORDORDER */
120 
121 
122 #include "begin_code.h"
123 /* Set up for C function definitions, even when using C++ */
124 #ifdef __cplusplus
125 extern "C" {
126 #endif
127 
128 /**
129  *  \file SDL_endian.h
130  */
131 
132 /* various modern compilers may have builtin swap */
133 #if defined(__GNUC__) || defined(__clang__)
134 #   define HAS_BUILTIN_BSWAP16 (_SDL_HAS_BUILTIN(__builtin_bswap16)) || \
135         (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
136 #   define HAS_BUILTIN_BSWAP32 (_SDL_HAS_BUILTIN(__builtin_bswap32)) || \
137         (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
138 #   define HAS_BUILTIN_BSWAP64 (_SDL_HAS_BUILTIN(__builtin_bswap64)) || \
139         (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
140 
141     /* this one is broken */
142 #   define HAS_BROKEN_BSWAP (__GNUC__ == 2 && __GNUC_MINOR__ <= 95)
143 #else
144 #   define HAS_BUILTIN_BSWAP16 0
145 #   define HAS_BUILTIN_BSWAP32 0
146 #   define HAS_BUILTIN_BSWAP64 0
147 #   define HAS_BROKEN_BSWAP 0
148 #endif
149 
150 #if HAS_BUILTIN_BSWAP16
151 #define SDL_Swap16(x) __builtin_bswap16(x)
152 #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
153 #pragma intrinsic(_byteswap_ushort)
154 #define SDL_Swap16(x) _byteswap_ushort(x)
155 #elif defined(__i386__) && !HAS_BROKEN_BSWAP
156 SDL_FORCE_INLINE Uint16
157 SDL_Swap16(Uint16 x)
158 {
159   __asm__("xchgb %b0,%h0": "=q"(x):"0"(x));
160     return x;
161 }
162 #elif defined(__x86_64__)
163 SDL_FORCE_INLINE Uint16
164 SDL_Swap16(Uint16 x)
165 {
166   __asm__("xchgb %b0,%h0": "=Q"(x):"0"(x));
167     return x;
168 }
169 #elif (defined(__powerpc__) || defined(__ppc__))
170 SDL_FORCE_INLINE Uint16
171 SDL_Swap16(Uint16 x)
172 {
173     int result;
174 
175   __asm__("rlwimi %0,%2,8,16,23": "=&r"(result):"0"(x >> 8), "r"(x));
176     return (Uint16)result;
177 }
178 #elif (defined(__m68k__) && !defined(__mcoldfire__))
179 SDL_FORCE_INLINE Uint16
180 SDL_Swap16(Uint16 x)
181 {
182   __asm__("rorw #8,%0": "=d"(x): "0"(x):"cc");
183     return x;
184 }
185 #elif defined(__WATCOMC__) && defined(__386__)
186 extern __inline Uint16 SDL_Swap16(Uint16);
187 #pragma aux SDL_Swap16 = \
188   "xchg al, ah" \
189   parm   [ax]   \
190   modify [ax];
191 #else
192 
193 /**
194  * Use this function to swap the byte order of a 16-bit value.
195  *
196  * \param x the value to be swapped.
197  * \returns the swapped value.
198  *
199  * \sa SDL_SwapBE16
200  * \sa SDL_SwapLE16
201  */
202 SDL_FORCE_INLINE Uint16
203 SDL_Swap16(Uint16 x)
204 {
205     return SDL_static_cast(Uint16, ((x << 8) | (x >> 8)));
206 }
207 #endif
208 
209 #if HAS_BUILTIN_BSWAP32
210 #define SDL_Swap32(x) __builtin_bswap32(x)
211 #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
212 #pragma intrinsic(_byteswap_ulong)
213 #define SDL_Swap32(x) _byteswap_ulong(x)
214 #elif defined(__i386__) && !HAS_BROKEN_BSWAP
215 SDL_FORCE_INLINE Uint32
216 SDL_Swap32(Uint32 x)
217 {
218   __asm__("bswap %0": "=r"(x):"0"(x));
219     return x;
220 }
221 #elif defined(__x86_64__)
222 SDL_FORCE_INLINE Uint32
223 SDL_Swap32(Uint32 x)
224 {
225   __asm__("bswapl %0": "=r"(x):"0"(x));
226     return x;
227 }
228 #elif (defined(__powerpc__) || defined(__ppc__))
229 SDL_FORCE_INLINE Uint32
230 SDL_Swap32(Uint32 x)
231 {
232     Uint32 result;
233 
234   __asm__("rlwimi %0,%2,24,16,23": "=&r"(result): "0" (x>>24),  "r"(x));
235   __asm__("rlwimi %0,%2,8,8,15"  : "=&r"(result): "0" (result), "r"(x));
236   __asm__("rlwimi %0,%2,24,0,7"  : "=&r"(result): "0" (result), "r"(x));
237     return result;
238 }
239 #elif (defined(__m68k__) && !defined(__mcoldfire__))
240 SDL_FORCE_INLINE Uint32
241 SDL_Swap32(Uint32 x)
242 {
243   __asm__("rorw #8,%0\n\tswap %0\n\trorw #8,%0": "=d"(x): "0"(x):"cc");
244     return x;
245 }
246 #elif defined(__WATCOMC__) && defined(__386__)
247 extern __inline Uint32 SDL_Swap32(Uint32);
248 #pragma aux SDL_Swap32 = \
249   "bswap eax"  \
250   parm   [eax] \
251   modify [eax];
252 #else
253 
254 /**
255  * Use this function to swap the byte order of a 32-bit value.
256  *
257  * \param x the value to be swapped.
258  * \returns the swapped value.
259  *
260  * \sa SDL_SwapBE32
261  * \sa SDL_SwapLE32
262  */
263 SDL_FORCE_INLINE Uint32
264 SDL_Swap32(Uint32 x)
265 {
266     return SDL_static_cast(Uint32, ((x << 24) | ((x << 8) & 0x00FF0000) |
267                                     ((x >> 8) & 0x0000FF00) | (x >> 24)));
268 }
269 #endif
270 
271 #if HAS_BUILTIN_BSWAP64
272 #define SDL_Swap64(x) __builtin_bswap64(x)
273 #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
274 #pragma intrinsic(_byteswap_uint64)
275 #define SDL_Swap64(x) _byteswap_uint64(x)
276 #elif defined(__i386__) && !HAS_BROKEN_BSWAP
277 SDL_FORCE_INLINE Uint64
278 SDL_Swap64(Uint64 x)
279 {
280     union {
281         struct {
282             Uint32 a, b;
283         } s;
284         Uint64 u;
285     } v;
286     v.u = x;
287   __asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1"
288           : "=r"(v.s.a), "=r"(v.s.b)
289           : "0" (v.s.a),  "1"(v.s.b));
290     return v.u;
291 }
292 #elif defined(__x86_64__)
293 SDL_FORCE_INLINE Uint64
294 SDL_Swap64(Uint64 x)
295 {
296   __asm__("bswapq %0": "=r"(x):"0"(x));
297     return x;
298 }
299 #elif defined(__WATCOMC__) && defined(__386__)
300 extern __inline Uint64 SDL_Swap64(Uint64);
301 #pragma aux SDL_Swap64 = \
302   "bswap eax"     \
303   "bswap edx"     \
304   "xchg eax,edx"  \
305   parm [eax edx]  \
306   modify [eax edx];
307 #else
308 
309 /**
310  * Use this function to swap the byte order of a 64-bit value.
311  *
312  * \param x the value to be swapped.
313  * \returns the swapped value.
314  *
315  * \sa SDL_SwapBE64
316  * \sa SDL_SwapLE64
317  */
318 SDL_FORCE_INLINE Uint64
319 SDL_Swap64(Uint64 x)
320 {
321     Uint32 hi, lo;
322 
323     /* Separate into high and low 32-bit values and swap them */
324     lo = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
325     x >>= 32;
326     hi = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
327     x = SDL_Swap32(lo);
328     x <<= 32;
329     x |= SDL_Swap32(hi);
330     return (x);
331 }
332 #endif
333 
334 
335 /**
336  * Use this function to swap the byte order of a floating point value.
337  *
338  * \param x the value to be swapped.
339  * \returns the swapped value.
340  *
341  * \sa SDL_SwapFloatBE
342  * \sa SDL_SwapFloatLE
343  */
344 SDL_FORCE_INLINE float
SDL_SwapFloat(float x)345 SDL_SwapFloat(float x)
346 {
347     union {
348         float f;
349         Uint32 ui32;
350     } swapper;
351     swapper.f = x;
352     swapper.ui32 = SDL_Swap32(swapper.ui32);
353     return swapper.f;
354 }
355 
356 /* remove extra macros */
357 #undef HAS_BROKEN_BSWAP
358 #undef HAS_BUILTIN_BSWAP16
359 #undef HAS_BUILTIN_BSWAP32
360 #undef HAS_BUILTIN_BSWAP64
361 
362 /**
363  *  \name Swap to native
364  *  Byteswap item from the specified endianness to the native endianness.
365  */
366 /* @{ */
367 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
368 #define SDL_SwapLE16(X)     (X)
369 #define SDL_SwapLE32(X)     (X)
370 #define SDL_SwapLE64(X)     (X)
371 #define SDL_SwapFloatLE(X)  (X)
372 #define SDL_SwapBE16(X)     SDL_Swap16(X)
373 #define SDL_SwapBE32(X)     SDL_Swap32(X)
374 #define SDL_SwapBE64(X)     SDL_Swap64(X)
375 #define SDL_SwapFloatBE(X)  SDL_SwapFloat(X)
376 #else
377 #define SDL_SwapLE16(X)     SDL_Swap16(X)
378 #define SDL_SwapLE32(X)     SDL_Swap32(X)
379 #define SDL_SwapLE64(X)     SDL_Swap64(X)
380 #define SDL_SwapFloatLE(X)  SDL_SwapFloat(X)
381 #define SDL_SwapBE16(X)     (X)
382 #define SDL_SwapBE32(X)     (X)
383 #define SDL_SwapBE64(X)     (X)
384 #define SDL_SwapFloatBE(X)  (X)
385 #endif
386 /* @} *//* Swap to native */
387 
388 /* Ends C function definitions when using C++ */
389 #ifdef __cplusplus
390 }
391 #endif
392 #include "close_code.h"
393 
394 #endif /* SDL_endian_h_ */
395 
396 /* vi: set ts=4 sw=4 expandtab: */