1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2024 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 | * \file SDL_endian.h |
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__)) |
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(__OpenBSD__) || defined(__DragonFly__) |
63 | #include <endian.h> |
64 | #define SDL_BYTEORDER BYTE_ORDER |
65 | #elif defined(__FreeBSD__) || defined(__NetBSD__) |
66 | #include <sys/endian.h> |
67 | #define SDL_BYTEORDER BYTE_ORDER |
68 | /* predefs from newer gcc and clang versions: */ |
69 | #elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__) |
70 | #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) |
71 | #define SDL_BYTEORDER SDL_LIL_ENDIAN |
72 | #elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
73 | #define SDL_BYTEORDER SDL_BIG_ENDIAN |
74 | #else |
75 | #error Unsupported endianness |
76 | #endif /**/ |
77 | #else |
78 | #if defined(__hppa__) || \ |
79 | defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ |
80 | (defined(__MIPS__) && defined(__MIPSEB__)) || \ |
81 | defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \ |
82 | defined(__sparc__) |
83 | #define SDL_BYTEORDER SDL_BIG_ENDIAN |
84 | #else |
85 | #define SDL_BYTEORDER SDL_LIL_ENDIAN |
86 | #endif |
87 | #endif /* __linux__ */ |
88 | #endif /* !SDL_BYTEORDER */ |
89 | |
90 | #ifndef SDL_FLOATWORDORDER /* Not defined in SDL_config.h? */ |
91 | /* predefs from newer gcc versions: */ |
92 | #if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__) |
93 | #if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) |
94 | #define SDL_FLOATWORDORDER SDL_LIL_ENDIAN |
95 | #elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__) |
96 | #define SDL_FLOATWORDORDER SDL_BIG_ENDIAN |
97 | #else |
98 | #error Unsupported endianness |
99 | #endif /**/ |
100 | #elif defined(__MAVERICK__) |
101 | /* For Maverick, float words are always little-endian. */ |
102 | #define SDL_FLOATWORDORDER SDL_LIL_ENDIAN |
103 | #elif (defined(__arm__) || defined(__thumb__)) && !defined(__VFP_FP__) && !defined(__ARM_EABI__) |
104 | /* For FPA, float words are always big-endian. */ |
105 | #define SDL_FLOATWORDORDER SDL_BIG_ENDIAN |
106 | #else |
107 | /* By default, assume that floats words follow the memory system mode. */ |
108 | #define SDL_FLOATWORDORDER SDL_BYTEORDER |
109 | #endif /* __FLOAT_WORD_ORDER__ */ |
110 | #endif /* !SDL_FLOATWORDORDER */ |
111 | |
112 | |
113 | #include "begin_code.h" |
114 | /* Set up for C function definitions, even when using C++ */ |
115 | #ifdef __cplusplus |
116 | extern "C" { |
117 | #endif |
118 | |
119 | /** |
120 | * \file SDL_endian.h |
121 | */ |
122 | |
123 | /* various modern compilers may have builtin swap */ |
124 | #if defined(__GNUC__) || defined(__clang__) |
125 | # define HAS_BUILTIN_BSWAP16 (_SDL_HAS_BUILTIN(__builtin_bswap16)) || \ |
126 | (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) |
127 | # define HAS_BUILTIN_BSWAP32 (_SDL_HAS_BUILTIN(__builtin_bswap32)) || \ |
128 | (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) |
129 | # define HAS_BUILTIN_BSWAP64 (_SDL_HAS_BUILTIN(__builtin_bswap64)) || \ |
130 | (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) |
131 | |
132 | /* this one is broken */ |
133 | # define HAS_BROKEN_BSWAP (__GNUC__ == 2 && __GNUC_MINOR__ <= 95) |
134 | #else |
135 | # define HAS_BUILTIN_BSWAP16 0 |
136 | # define HAS_BUILTIN_BSWAP32 0 |
137 | # define HAS_BUILTIN_BSWAP64 0 |
138 | # define HAS_BROKEN_BSWAP 0 |
139 | #endif |
140 | |
141 | #if HAS_BUILTIN_BSWAP16 |
142 | #define SDL_Swap16(x) __builtin_bswap16(x) |
143 | #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL) |
144 | #pragma intrinsic(_byteswap_ushort) |
145 | #define SDL_Swap16(x) _byteswap_ushort(x) |
146 | #elif defined(__i386__) && !HAS_BROKEN_BSWAP |
147 | SDL_FORCE_INLINE Uint16 |
148 | SDL_Swap16(Uint16 x) |
149 | { |
150 | __asm__("xchgb %b0,%h0" : "=q" (x):"0" (x)); |
151 | return x; |
152 | } |
153 | #elif defined(__x86_64__) |
154 | SDL_FORCE_INLINE Uint16 |
155 | SDL_Swap16(Uint16 x) |
156 | { |
157 | __asm__("xchgb %b0,%h0" : "=Q" (x):"0" (x)); |
158 | return x; |
159 | } |
160 | #elif (defined(__powerpc__) || defined(__ppc__)) |
161 | SDL_FORCE_INLINE Uint16 |
162 | SDL_Swap16(Uint16 x) |
163 | { |
164 | int result; |
165 | |
166 | __asm__("rlwimi %0,%2,8,16,23" : "=&r" (result):"0" (x >> 8), "r" (x)); |
167 | return (Uint16)result; |
168 | } |
169 | #elif (defined(__m68k__) && !defined(__mcoldfire__)) |
170 | SDL_FORCE_INLINE Uint16 |
171 | SDL_Swap16(Uint16 x) |
172 | { |
173 | __asm__("rorw #8,%0" : "=d" (x): "0" (x):"cc" ); |
174 | return x; |
175 | } |
176 | #elif defined(__WATCOMC__) && defined(__386__) |
177 | extern __inline Uint16 SDL_Swap16(Uint16); |
178 | #pragma aux SDL_Swap16 = \ |
179 | "xchg al, ah" \ |
180 | parm [ax] \ |
181 | modify [ax]; |
182 | #else |
183 | SDL_FORCE_INLINE Uint16 |
184 | SDL_Swap16(Uint16 x) |
185 | { |
186 | return SDL_static_cast(Uint16, ((x << 8) | (x >> 8))); |
187 | } |
188 | #endif |
189 | |
190 | #if HAS_BUILTIN_BSWAP32 |
191 | #define SDL_Swap32(x) __builtin_bswap32(x) |
192 | #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL) |
193 | #pragma intrinsic(_byteswap_ulong) |
194 | #define SDL_Swap32(x) _byteswap_ulong(x) |
195 | #elif defined(__i386__) && !HAS_BROKEN_BSWAP |
196 | SDL_FORCE_INLINE Uint32 |
197 | SDL_Swap32(Uint32 x) |
198 | { |
199 | __asm__("bswap %0" : "=r" (x):"0" (x)); |
200 | return x; |
201 | } |
202 | #elif defined(__x86_64__) |
203 | SDL_FORCE_INLINE Uint32 |
204 | SDL_Swap32(Uint32 x) |
205 | { |
206 | __asm__("bswapl %0" : "=r" (x):"0" (x)); |
207 | return x; |
208 | } |
209 | #elif (defined(__powerpc__) || defined(__ppc__)) |
210 | SDL_FORCE_INLINE Uint32 |
211 | SDL_Swap32(Uint32 x) |
212 | { |
213 | Uint32 result; |
214 | |
215 | __asm__("rlwimi %0,%2,24,16,23" : "=&r" (result): "0" (x>>24), "r" (x)); |
216 | __asm__("rlwimi %0,%2,8,8,15" : "=&r" (result): "0" (result), "r" (x)); |
217 | __asm__("rlwimi %0,%2,24,0,7" : "=&r" (result): "0" (result), "r" (x)); |
218 | return result; |
219 | } |
220 | #elif (defined(__m68k__) && !defined(__mcoldfire__)) |
221 | SDL_FORCE_INLINE Uint32 |
222 | SDL_Swap32(Uint32 x) |
223 | { |
224 | __asm__("rorw #8,%0\n\tswap %0\n\trorw #8,%0" : "=d" (x): "0" (x):"cc" ); |
225 | return x; |
226 | } |
227 | #elif defined(__WATCOMC__) && defined(__386__) |
228 | extern __inline Uint32 SDL_Swap32(Uint32); |
229 | #pragma aux SDL_Swap32 = \ |
230 | "bswap eax" \ |
231 | parm [eax] \ |
232 | modify [eax]; |
233 | #else |
234 | SDL_FORCE_INLINE Uint32 |
235 | SDL_Swap32(Uint32 x) |
236 | { |
237 | return SDL_static_cast(Uint32, ((x << 24) | ((x << 8) & 0x00FF0000) | |
238 | ((x >> 8) & 0x0000FF00) | (x >> 24))); |
239 | } |
240 | #endif |
241 | |
242 | #if HAS_BUILTIN_BSWAP64 |
243 | #define SDL_Swap64(x) __builtin_bswap64(x) |
244 | #elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL) |
245 | #pragma intrinsic(_byteswap_uint64) |
246 | #define SDL_Swap64(x) _byteswap_uint64(x) |
247 | #elif defined(__i386__) && !HAS_BROKEN_BSWAP |
248 | SDL_FORCE_INLINE Uint64 |
249 | SDL_Swap64(Uint64 x) |
250 | { |
251 | union { |
252 | struct { |
253 | Uint32 a, b; |
254 | } s; |
255 | Uint64 u; |
256 | } v; |
257 | v.u = x; |
258 | __asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1" |
259 | : "=r" (v.s.a), "=r" (v.s.b) |
260 | : "0" (v.s.a), "1" (v.s.b)); |
261 | return v.u; |
262 | } |
263 | #elif defined(__x86_64__) |
264 | SDL_FORCE_INLINE Uint64 |
265 | SDL_Swap64(Uint64 x) |
266 | { |
267 | __asm__("bswapq %0" : "=r" (x):"0" (x)); |
268 | return x; |
269 | } |
270 | #elif defined(__WATCOMC__) && defined(__386__) |
271 | extern __inline Uint64 SDL_Swap64(Uint64); |
272 | #pragma aux SDL_Swap64 = \ |
273 | "bswap eax" \ |
274 | "bswap edx" \ |
275 | "xchg eax,edx" \ |
276 | parm [eax edx] \ |
277 | modify [eax edx]; |
278 | #else |
279 | SDL_FORCE_INLINE Uint64 |
280 | SDL_Swap64(Uint64 x) |
281 | { |
282 | Uint32 hi, lo; |
283 | |
284 | /* Separate into high and low 32-bit values and swap them */ |
285 | lo = SDL_static_cast(Uint32, x & 0xFFFFFFFF); |
286 | x >>= 32; |
287 | hi = SDL_static_cast(Uint32, x & 0xFFFFFFFF); |
288 | x = SDL_Swap32(lo); |
289 | x <<= 32; |
290 | x |= SDL_Swap32(hi); |
291 | return (x); |
292 | } |
293 | #endif |
294 | |
295 | |
296 | SDL_FORCE_INLINE float |
297 | SDL_SwapFloat(float x) |
298 | { |
299 | union { |
300 | float f; |
301 | Uint32 ui32; |
302 | } swapper; |
303 | swapper.f = x; |
304 | swapper.ui32 = SDL_Swap32(swapper.ui32); |
305 | return swapper.f; |
306 | } |
307 | |
308 | /* remove extra macros */ |
309 | #undef HAS_BROKEN_BSWAP |
310 | #undef HAS_BUILTIN_BSWAP16 |
311 | #undef HAS_BUILTIN_BSWAP32 |
312 | #undef HAS_BUILTIN_BSWAP64 |
313 | |
314 | /** |
315 | * \name Swap to native |
316 | * Byteswap item from the specified endianness to the native endianness. |
317 | */ |
318 | /* @{ */ |
319 | #if SDL_BYTEORDER == SDL_LIL_ENDIAN |
320 | #define SDL_SwapLE16(X) (X) |
321 | #define SDL_SwapLE32(X) (X) |
322 | #define SDL_SwapLE64(X) (X) |
323 | #define SDL_SwapFloatLE(X) (X) |
324 | #define SDL_SwapBE16(X) SDL_Swap16(X) |
325 | #define SDL_SwapBE32(X) SDL_Swap32(X) |
326 | #define SDL_SwapBE64(X) SDL_Swap64(X) |
327 | #define SDL_SwapFloatBE(X) SDL_SwapFloat(X) |
328 | #else |
329 | #define SDL_SwapLE16(X) SDL_Swap16(X) |
330 | #define SDL_SwapLE32(X) SDL_Swap32(X) |
331 | #define SDL_SwapLE64(X) SDL_Swap64(X) |
332 | #define SDL_SwapFloatLE(X) SDL_SwapFloat(X) |
333 | #define SDL_SwapBE16(X) (X) |
334 | #define SDL_SwapBE32(X) (X) |
335 | #define SDL_SwapBE64(X) (X) |
336 | #define SDL_SwapFloatBE(X) (X) |
337 | #endif |
338 | /* @} *//* Swap to native */ |
339 | |
340 | /* Ends C function definitions when using C++ */ |
341 | #ifdef __cplusplus |
342 | } |
343 | #endif |
344 | #include "close_code.h" |
345 | |
346 | #endif /* SDL_endian_h_ */ |
347 | |
348 | /* vi: set ts=4 sw=4 expandtab: */ |
349 | |