SH4ZAM! 0.9.1
Fast math library for the Sega Dreamcast's SH4 CPU
Loading...
Searching...
No Matches
shz_cdefs.h
Go to the documentation of this file.
1/*! \file
2 * \brief Preprocessor definitions and macro utilities.
3 *
4 * This file contains commonly used preprocessor definitions used throughout
5 * the project:
6 * - Library-wide configuration defines
7 * - Compiler detection
8 * - Compiler attributes
9 * - TLS model
10 * - Conversion utilities
11 *
12 * \author 2025, 2026 Falco Girgis
13 * \copyright MIT License
14 */
15
16#ifndef SHZ_CDEFS_H
17#define SHZ_CDEFS_H
18
19#include <stdint.h>
20#include <assert.h>
21
22#ifdef __cplusplus
23# include <type_traits>
24#endif
25
26/*! \name Back-Ends
27 \brief List of architectures which SH4ZAM can auto-detect.
28 @{
29*/
30#define SHZ_SH4 1 //!< Back-end for the Dreamcast's SH4.
31#define SHZ_PPC 2 //!< Back-end for the Gamecube/Wii's Gekko PPC.
32#define SHZ_MIPS 3 //!< Back-end for MIPS architectures
33#define SHZ_ARM 4 //!< Back-end for ARM architectures.
34#define SHZ_X86_64 5 //!< Back-end for x86_64 architectures.
35#define SHZ_SPU 6 //!< Back-end for the Cell B/E SPU architecture.
36#define SHZ_WASM 8 //!< Back-end for WebAssembly.
37#define SHZ_SW ~0 //!< Generic C-based software back-end.
38//! @}
39
40// Determine the actual architecture we're targeting.
41#ifndef SHZ_TARGET
42# if defined(__SH__) || defined(__sh__)
43# define SHZ_TARGET SHZ_SH4
44# elif defined(__powerpc__) || defined(__PPC__) || defined(_ARCH_PPC)
45# define SHZ_TARGET SHZ_PPC
46# elif defined(_mips) || defined(__mips)
47# define SHZ_TARGET SHZ_MIPS
48# elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
49# define SHZ_TARGET SHZ_ARM
50# elif defined(__x86_64__) || defined(_M_X64)
51# define SHZ_TARGET SHZ_X86_64
52# elif defined(__SPU__)
53# define SHZ_TARGET SHZ_SPU
54# elif defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__)
55# define SHZ_TARGET SHZ_WASM
56# else
57# define SHZ_TARGET SHZ_SW
58# endif
59#endif
60
61// Attempt to detect default back-end for the given build target.
62#ifndef SHZ_BACKEND
63# if SHZ_TARGET == SHZ_SH4 && (defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__))
64# define SHZ_BACKEND SHZ_SH4 // Dreamcast builds use SH4 back-end ONLY in single-precision FPU mode.
65# elif SHZ_TARGET == SHZ_SPU
66# define SHZ_BACKEND SHZ_SPU
67# else
68# define SHZ_BACKEND SHZ_SW // Everything else uses SW C back-end right now.
69# endif
70#endif
71
72/*! \name TLS Models
73 \brief Defines for different mechanisms for thread-local storage.
74 @{
75*/
76#define SHZ_TLS_DISABLED 0 //!< No thread-local variables.
77#define SHZ_TLS_IMPLICIT 1 //!< Use `thread_local` keyword for TLS.
78#define SHZ_TLS_PTHREAD 2 //!< Use pthread unique keys for TLS.
79#define SHZ_TLS_CTHREAD 3 //!< Use C11 thread TSS keys for TLS.
80//! @}
81
82// Attempt to detect default TLS model for the given back-end.
83#ifndef SHZ_TLS_MODEL
84# if SHZ_TARGET == SHZ_SH4
85# define SHZ_TLS_MODEL SHZ_TLS_IMPLICIT // SH4 toolchain supports compiler-level TLS.
87# define SHZ_TLS_MODEL SHZ_TLS_DISABLED // SPU + PPC toolchains don't support TLS.
88# else
89# define SHZ_TLS_MODEL SHZ_TLS_PTHREAD // SW target uses pthread-based TLS for compatibilty.
90# endif
91#endif
92
93/*! \name Compiler Detection
94 \brief Defines for identifying the detected compiler.
95 @{
96*/
97#ifdef _MSC_VER
98# define SHZ_MSVC 1 //!< Defined when building with Microsoft Visual C++.
99#elif defined(__GNUC__)
100# define SHZ_GNUC 1 //!< Defined when building with a GCC-compatible compiler.
101# if defined(__clang__)
102# define SHZ_CLANG 1 //!< Defined when bulding with Clang.
103# elif defined(__MINGW64__)
104# define SHZ_MINGW64 1 //!< Defined when bulding with MinGW-w64.
105# elif defined(__MINGW32__)
106# define SHZ_MINGW32 1 //!< Defined when building for 32-bit MinGW or other MinGW compiler(s).
107# else
108# define SHZ_GCC 1 //!< Defined when building for GCC.
109# endif
110#else
111# define SHZ_GNUC 1 // Unknown compiler -- assume it's GCC-compatible?
112#endif
113//! @}
114
115/*! \name Utilities
116 * \brief Miscellaneous function-like macros
117 * @{
118 */
119//! Stringifies a literal expression.
120#define SHZ_STRINGIFY_LITERAL(a) #a
121 //! Stringifies an expression _after_ preprocessing, supporting macro expansion.
122#define SHZ_STRINGIFY(a) SHZ_STRINGIFY_LITERAL(a)
123//! Returns the number of elements within a statically sized array
124#define SHZ_COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
125//! Returns the containing structure from a pointer to one of its members
126#define SHZ_CONTAINER_OF(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type, member)))
127//! Macro which swaps the two values held by \p a and \p b.
128#define SHZ_SWAP(a, b) do { typeof(a) tmp = a; a = b; b = tmp; } while(false)
129//! Macro which forward declares a struct and its typedef.
130#define SHZ_DECLARE_STRUCT(n, t) struct n; typedef struct n t
131//! Macro which forward declares a manually aligned struct and its typedef.
132#define SHZ_DECLARE_STRUCT_ALIGNED(n, t, a) struct SHZ_ALIGNAS(a) n; typedef struct n t
133//! @}
134
135//! \cond
136/*! \name Compiler attributes
137 * \brief Defines for commonly-used GCC attributes.
138 * @{
139 */
140#ifdef SHZ_GNUC
141 //! Forces a function or type to be aligned by \p N bytes.
142# define SHZ_ALIGNAS(N) __attribute__((aligned((N))))
143 //! Tells GCC that a scalar type is to be treated as a vector of size \p N.
144# define SHZ_SIMD(N) __attribute__((vector_size((N))))
145 //! Tells GCC that a particular function should be optimized for performance.
146# define SHZ_HOT __attribute__((hot))
147 //! Tells GCC that a particular function should be optimized for size.
148# define SHZ_COLD __attribute__((cold))
149 //! Put this before a function definition to tell GCC to use fast math optimizations on a specific function.
150# define SHZ_FAST_MATH __attribute__((optimize("fast-math")))
151 //! Put this before a function definition to tell GCC to NOT use fast math optimizations on a specific function.
152# define SHZ_NO_FAST_MATH __attribute__((optimize("no-fast-math")))
153 //! Put this before a function definition to tell GCC to NOT unroll loops in a specific function.
154# define SHZ_NO_UNROLL_LOOPS __attribute__((optimize("no-unroll-loops")))
155 //! Tells GCC to disable any optimizations when compiling a function.
156# define SHZ_NO_OPTIMIZATION __attribute__((optimize("O0")))
157 //! Aligns a function within the .text segment by \p N bytes.
158# define SHZ_FUNC_ALIGNAS(N) __attribute__((aligned(N)))
159 //! Forces GCC to inline the given function.
160# define SHZ_FORCE_INLINE __attribute__((always_inline)) SHZ_INLINE
161 //! Prevents GCC from inlining the given function.
162# define SHZ_NO_INLINE __attribute__((noinline))
163 //! Forces GCC to inline all calls to other functions made within the tagged function.
164# define SHZ_FLATTEN __attribute__((flatten))
165 //! Tells GCC not to introduce any extra padding for the given type.
166# define SHZ_PACKED __attribute__((packed))
167 //! Tells GCC the function has no effects other than returning a value that depends on its arguments and global variables.
168# define SHZ_PURE __attribute__((pure))
169 //! Tells GCC the function has no effects other than returning a value that depends only on its arguments.
170# define SHZ_CONST __attribute__((const))
171 //! Tells GCC that the decorated pointer may be breaking strict aliasing rules for C and C++
172# define SHZ_ALIASING __attribute__((__may_alias__))
173 //! Emits a warning that a symbol has been deprecated with a message, upon use.
174# define SHZ_DEPRECATED(m) __attribute__((deprecated(m)))
175 //! Tells GCC that the expression is likely to be true (used for conditional and loop optimizations)
176# define SHZ_LIKELY(e) __builtin_expect(!!(e), 1)
177 //! Tells GCC that the expression is likely to be false (used for conditional and loop optimizations)
178# define SHZ_UNLIKELY(e) __builtin_expect(!!(e), 0)
179 //! Tells GCC the pointer paraemter is unique and is not aliased by another parameter
180# define SHZ_RESTRICT __restrict__
181 //! Creates a software memory barrier beyond which any loads or stores may not be reordered
182# define SHZ_MEMORY_BARRIER_SOFT() asm volatile("" : : : "memory")
183 //! Creates a hardware memory barrier beyond which any loads or stores may not be reordered
184# define SHZ_MEMORY_BARRIER_HARD() __sync_synchronize()
185 //! Prevents the compiler from reordering instructions beyond the barrier.
186# define SHZ_INSTR_BARRIER() asm volatile("")
187#elif defined(SHZ_MSVC)
188 //! Forces a function or type to be aligned by \p N bytes.
189# define SHZ_ALIGNAS(N) __declspec(align(N))
190 //! Unsupported by MSVC.
191# define SHZ_SIMD(N) [N/4]
192 //! Unsupported by MSVC.
193# define SHZ_HOT
194 //! Unsupported by MSVC.
195# define SHZ_COLD
196 //! Unsupported by MSVC.
197# define SHZ_FAST_MATH
198 //! Unsupported by MSVC.
199# define SHZ_NO_FAST_MATH
200 //! Unsupported by MSVC.
201# define SHZ_NO_UNROLL_LOOPS
202 //! Unsupported by MSVC.
203# define SHZ_NO_OPTIMIZATION
204 //! Unsupported by MSVC.
205# define SHZ_FUNC_ALIGNAS(N)
206 //! Forces MSVC to inline the given function.
207# define SHZ_FORCE_INLINE __forceinline
208 //! Prevents MSVC from inlining the given function.
209# define SHZ_NO_INLINE __declspec(noinline)
210 //! Unsupported by MSVC.
211# define SHZ_FLATTEN
212 //! Unimplemented for MSVC.
213# define SHZ_PACKED
214 //! Unsupported by MSVC.
215# define SHZ_PURE SHZ_CONST
216 //! Tells MSVC that a function may be evaluated at compile-time.
217# define SHZ_CONST constexpr
218 //! MSVC already doesn't optimize for strict aliasing rules.
219# define SHZ_ALIASING
220 //! Emits a warning that a symbol has been deprecated with a message, upon use.
221# define SHZ_DEPRECATED(m) __declspec(deprecated(m))
222 //! Unimplemented for MSVC.
223# define SHZ_LIKELY(e) (e)
224 //! Unimplemented for MSVC.
225# define SHZ_UNLIKELY(e) (e)
226 //! Tells MSVC the pointer paraemter is unique and is not aliased by another parameter.
227# define SHZ_RESTRICT __restrict
228 //! Unimplemented for MSVC.
229# define SHZ_MEMORY_BARRIER_SOFT()
230 //! Unimpemented for MSVC.
231# define SHZ_MEMORY_BARRIER_HARD()
232 //! Prevents the compiler from reordering instructions beyond the barrier.
233# define SHZ_INSTR_BARRIER()
234#endif
235
236#ifndef __cplusplus
237 //! Dummy define provided for C++ compatibility
238# define SHZ_DECLS_BEGIN
239 //! Dummy define provided for C++ compatibility
240# define SHZ_DECLS_END
241 //! Requests a function or member to be inlined (nonforcibly) OR to have static linkage.
242# define SHZ_INLINE inline static
243 //! Dummy define provided for C++ compatibility
244# define SHZ_NOEXCEPT
245 //! Temporary struct initialization statement to use within C.
246#if defined(SHZ_MSVC)
247# define SHZ_INIT(type, ...) ((type){ __VA_ARGS__ })
248#else
249# define SHZ_INIT(type, ...) ({ type r = { __VA_ARGS__ }; r; })
250#endif
251 //! Conversion macro for zero-overhead conversions, taking the given \p value to a value of the given \p type.
252# define SHZ_CONVERT(type, value)
253 (((struct {
254 union {
255 typeof(value) from;
256 type to;
257 };
258 static_assert(sizeof(type) == sizeof(value), "SHZ_CONVERT: Cannot convert between types of differing sizes.");
259 }){ (value) }).to)
260#else
261 //! Forces functions declared after this directive to use C linkage.
262# define SHZ_DECLS_BEGIN extern "C" {
263 //! Ends forcing functions to use C linkage.
264# define SHZ_DECLS_END }
265 //! Requests a function or member to be inlined (nonforcibly).
266# define SHZ_INLINE inline
267 //! Tells the compiler that the function does not throw exceptions
268# define SHZ_NOEXCEPT noexcept
269 //! Temporary struct initialization statement to use within C++.
270#if defined(SHZ_MSVC)
271# define SHZ_INIT(type, ...) (type{ __VA_ARGS__ })
272#else
273# define SHZ_INIT(type, ...) ({ type r = { __VA_ARGS__ }; r; })
274#endif
275 //! Conversion macro for zero-overhead conversions that handles pointers/references \p from and \p type.
276# define SHZ_CONVERT(type, from)
277 [&]<typename To, typename V>(V&& value) -> To {
278 using TNR = std::remove_reference_t<To>;
279 using VNR = std::remove_reference_t<V>;
280 if constexpr (std::is_pointer_v<To>) {
281 if constexpr (std::is_pointer_v<VNR>) {
282 return reinterpret_cast<To>(value);
283 } else {
284 return reinterpret_cast<To>(&value);
285 }
286 } else if constexpr (std::is_reference_v<To>) {
287 static_assert(sizeof(VNR) == sizeof(TNR), "SHZ_CONVERT: Cannot convert between types of differing sizes when converting to a reference type.");
288 return reinterpret_cast<To>(value);
289 } else {
290 static_assert(sizeof(VNR) == sizeof(TNR), "SHZ_CONVERT: Cannot convert between types of differing sizes.");
291 return reinterpret_cast<To&>(value);
292 }
293 }.template operator()<type>(from)
294#endif
295//! @}
296//! \endcond
297
298/*! \name TLS Utilities
299 \brief Macros for declaring and managing thread-local variables.
300 @{
301*/
303 //! Declares a TLS variable with disabled model (so not thread-local).
304# define SHZ_TLS_DECL(type, name, ...) static type name = __VA_ARGS__;
305 //! References a TLS variable, with disabled model.
306# define SHZ_TLS_REF(name) (&name)
308# if !defined(__cplusplus) && !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L)
309# include <threads.h>
310# define SHZ_THREAD_LOCAL _Thread_local
311# else
312# define SHZ_THREAD_LOCAL thread_local
313# endif
314 //! Declares a TLS variable with compiler-driven implicit TLS model.
315# define SHZ_TLS_DECL(type, name, ...) static SHZ_THREAD_LOCAL type name = __VA_ARGS__;
316 //! References a TLS variable with compiler-driven implicit TLS model.
317# define SHZ_TLS_REF(name) (&name)
319# include <pthread.h>
320# include <stdlib.h>
321 //! Declares a TLS variable using pthread thread-specific data.
322# define SHZ_TLS_DECL(type, name, ...)
323 static pthread_key_t name;
324 static void tls_##name##_init_(void) {
325 int res = pthread_key_create(&name, free);
326 (void)res; assert(!res);
327 }
328 static type* tls_##name##_ref_(void) {
329 static pthread_once_t once_ctrl = PTHREAD_ONCE_INIT;
330 int ret = pthread_once(&once_ctrl, tls_##name##_init_);
331 (void)ret; assert(!ret);
332 type* ptr = pthread_getspecific(name);
333 if(!ptr) {
334 ptr = (type *)malloc(sizeof(type));
335 assert(ptr);
336 type temp = __VA_ARGS__;
337 memcpy(ptr, &temp, sizeof(type));
338 ret = pthread_setspecific(name, ptr);
339 assert(!ret);
340 }
341 return ptr;
342 }
343 //! References a TLS variable using pthread thread-specific data.
344# define SHZ_TLS_REF(name) tls_##name##_ref_()
345#elif SHZ_TLS_MODEL == SHZ_TLS_CTHREAD
346# include <threads.h>
347# include <stdlib.h>
348 //! Declares a TLS variable using C11 thread-specific storage.
349# define SHZ_TLS_DECL(type, name, ...)
350 static tss_t name;
351 static void tls_##name##_init_(void) {
352 int res = tss_create(&name, free);
353 (void)res; assert(res == thrd_success);
354 }
355 static type* tls_##name##_ref_(void) {
356 static once_flag once_ctrl = ONCE_FLAG_INIT;
357 call_once(&once_ctrl, tls_##name##_init_);
358 type* ptr = (type *)tss_get(name);
359 if(!ptr) {
360 ptr = (type *)malloc(sizeof(type));
361 assert(ptr);
362 type temp = __VA_ARGS__;
363 memcpy(ptr, &temp, sizeof(type));
364 int res = tss_set(name, ptr);
365 (void)res; assert(res == thrd_success);
366 }
367 return ptr;
368 }
369 //! References a TLS variable using C11 thread-specific storage.
370# define SHZ_TLS_REF(name) tls_##name##_ref_()
371#endif
372//! @}
373
374/*! \name Aliasing Types
375 * \brief Types which may break C/C++'s strict aliasing rules
376 * @{
377 */
378//! int16_t type whose value may be aliased as another type.
379typedef SHZ_ALIASING int16_t shz_alias_int16_t;
380//! uint16_t type whose value may be aliased as another type.
381typedef SHZ_ALIASING uint16_t shz_alias_uint16_t;
382//! int32_t type whose value may be aliased as another type.
383typedef SHZ_ALIASING int32_t shz_alias_int32_t;
384//! uint32_t type whose value may be aliased as another type.
385typedef SHZ_ALIASING uint32_t shz_alias_uint32_t;
386//! float type whose value may be aliased as another type.
387typedef SHZ_ALIASING float shz_alias_float_t;
388//! int64_t type whose value may be aliased as another type.
389typedef SHZ_ALIASING int64_t shz_alias_int64_t;
390//! uint64_t type whose value may be aliased as another type.
391typedef SHZ_ALIASING uint64_t shz_alias_uint64_t;
392//! double type whose value may be aliased as another type.
393typedef SHZ_ALIASING double shz_alias_double_t;
394//! @}
395
396#endif // SHZ_CDEFS_H
#define SHZ_SH4
Back-end for the Dreamcast's SH4.
Definition shz_cdefs.h:30
#define SHZ_TARGET
Definition shz_cdefs.h:57
SHZ_ALIASING int16_t shz_alias_int16_t
int16_t type whose value may be aliased as another type.
Definition shz_cdefs.h:379
SHZ_ALIASING double shz_alias_double_t
double type whose value may be aliased as another type.
Definition shz_cdefs.h:393
#define SHZ_TLS_IMPLICIT
Use thread_local keyword for TLS.
Definition shz_cdefs.h:77
SHZ_ALIASING uint32_t shz_alias_uint32_t
uint32_t type whose value may be aliased as another type.
Definition shz_cdefs.h:385
#define SHZ_SW
Generic C-based software back-end.
Definition shz_cdefs.h:37
#define SHZ_STRINGIFY_LITERAL(a)
Stringifies a literal expression.
Definition shz_cdefs.h:120
#define SHZ_TLS_MODEL
Definition shz_cdefs.h:85
#define SHZ_X86_64
Back-end for x86_64 architectures.
Definition shz_cdefs.h:34
SHZ_ALIASING int64_t shz_alias_int64_t
int64_t type whose value may be aliased as another type.
Definition shz_cdefs.h:389
SHZ_ALIASING uint16_t shz_alias_uint16_t
uint16_t type whose value may be aliased as another type.
Definition shz_cdefs.h:381
SHZ_ALIASING int32_t shz_alias_int32_t
int32_t type whose value may be aliased as another type.
Definition shz_cdefs.h:383
SHZ_ALIASING uint64_t shz_alias_uint64_t
uint64_t type whose value may be aliased as another type.
Definition shz_cdefs.h:391
SHZ_ALIASING float shz_alias_float_t
float type whose value may be aliased as another type.
Definition shz_cdefs.h:387
#define SHZ_PPC
Back-end for the Gamecube/Wii's Gekko PPC.
Definition shz_cdefs.h:31
#define SHZ_SPU
Back-end for the Cell B/E SPU architecture.
Definition shz_cdefs.h:35
#define SHZ_GNUC
Definition shz_cdefs.h:111
#define SHZ_TLS_PTHREAD
Use pthread unique keys for TLS.
Definition shz_cdefs.h:78
#define SHZ_TLS_DISABLED
No thread-local variables.
Definition shz_cdefs.h:76