SH4ZAM! 0.1.0
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 Platform-specific SH4ZAM implementations.
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 5 //!< Back-end for x86/64 architectures.
35#define SHZ_WASM 8 //!< Back-end for WebAssembly.
36#define SHZ_SW ~0 //!< Generic C-based software back-end.
37//! @}
38
39// Attempt to detect default back-end for the given build environment.
40#ifndef SHZ_BACKEND
41# ifdef __DREAMCAST__
42# define SHZ_BACKEND SHZ_SH4 // Dreamcast builds use SH4 back-end.
43# else
44# define SHZ_BACKEND SHZ_SW // Everything else uses SW C back-end.
45# endif
46#endif
47
48/*! \name TLS Models
49 \brief Defines for different mechanisms for thread-local storage.
50 @{
51*/
52#define SHZ_TLS_DISABLED 0 //!< No thread-local variables.
53#define SHZ_TLS_IMPLICIT 1 //!< Use `thread_local` keyword for TLS.
54#define SHZ_TLS_PTHREAD 2 //!< Use pthread unique keys for TLS.
55#define SHZ_TLS_CTHREAD 3 //!< Use C11 thread TSS keys for TLS.
56//! @}
57
58// Attempt to detect default TLS model for the given back-end.
59#ifndef SHZ_TLS_MODEL
60# if SHZ_BACKEND == SHZ_SH4
61# define SHZ_TLS_MODEL SHZ_TLS_IMPLICIT // SH4 back-end supports compiler-level TLS.
62# elif SHZ_BACKEND == SHZ_SW
63# define SHZ_TLS_MODEL SHZ_TLS_PTHREAD // SW back-end uses pthread-based TLS for compatibilty.
64# endif
65#endif
66
67/*! \name Compiler Detection
68 \brief Defines for identifying the detected compiler.
69 @{
70*/
71#ifdef _MSC_VER
72# define SHZ_MSVC 1 //!< Defined when building with Microsoft Visual C++.
73#elif defined(__GNUC__)
74# define SHZ_GNUC 1 //!< Defined when building with a GCC-compatible compiler.
75# if defined(__clang__)
76# define SHZ_CLANG 1 //!< Defined when bulding with Clang.
77# elif defined(__MINGW64__)
78# define SHZ_MINGW64 1 //!< Defined when bulding with MinGW-w64.
79# elif defined(__MINGW32__)
80# define SHZ_MINGW32 1 //!< Defined when building for 32-bit MinGW or other MinGW compiler(s).
81# else
82# define SHZ_GCC 1 //!< Defined when building for GCC.
83# endif
84#else
85# define SHZ_GNUC 1 // Unknown compiler -- assume it's GCC-compatible?
86#endif
87//! @}
88
89/*! \name Utilities
90 * \brief Miscellaneous function-like macros
91 * @{
92 */
93//! Stringifies a literal expression.
94#define SHZ_STRINGIFY_LITERAL(a) #a
95 //! Stringifies an expression _after_ preprocessing, supporting macro expansion.
96#define SHZ_STRINGIFY(a) SHZ_STRINGIFY_LITERAL(a)
97//! Returns the number of elements within a statically sized array
98#define SHZ_COUNT_OF(array) (sizeof(array) / sizeof((array)[0]))
99//! Returns the containing structure from a pointer to one of its members
100#define SHZ_CONTAINER_OF(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type, member)))
101//! Macro which swaps the two values held by \p a and \p b.
102#define SHZ_SWAP(a, b) do { typeof(a) tmp = a; a = b; b = tmp; } while(false)
103//! Macro which forward declares a struct and its typedef.
104#define SHZ_DECLARE_STRUCT(n, t) struct n; typedef struct n t
105//! Macro which forward declares a manually aligned struct and its typedef.
106#define SHZ_DECLARE_STRUCT_ALIGNED(n, t, a) struct SHZ_ALIGNAS(a) n; typedef struct n t
107//! @}
108
109//! \cond
110/*! \name Compiler attributes
111 * \brief Defines for commonly-used GCC attributes.
112 * @{
113 */
114#ifdef SHZ_GNUC
115 //! Forces a function or type to be aligned by \p N bytes.
116# define SHZ_ALIGNAS(N) __attribute__((aligned((N))))
117 //! Tells GCC that a scalar type is to be treated as a vector of size \p N.
118# define SHZ_SIMD(N) __attribute__((vector_size((N))))
119 //! Tells GCC that a particular function should be optimized for performance.
120# define SHZ_HOT __attribute__((hot))
121 //! Tells GCC that a particular function should be optimized for size.
122# define SHZ_COLD __attribute__((cold))
123 //! Put this before a function definition to tell GCC to use fast math optimizations on a specific function.
124# define SHZ_FAST_MATH __attribute__((optimize("fast-math")))
125 //! Put this before a function definition to tell GCC to NOT use fast math optimizations on a specific function.
126# define SHZ_NO_FAST_MATH __attribute__((optimize("no-fast-math")))
127 //! Put this before a function definition to tell GCC to NOT unroll loops in a specific function.
128# define SHZ_NO_UNROLL_LOOPS __attribute__((optimize("no-unroll-loops")))
129 //! Tells GCC to disable any optimizations when compiling a function.
130# define SHZ_NO_OPTIMIZATION __attribute__((optimize("O0")))
131 //! Aligns a function within the .text segment by \p N bytes.
132# define SHZ_FUNC_ALIGNAS(N) __attribute__((aligned(N)))
133 //! Forces GCC to inline the given function.
134# define SHZ_FORCE_INLINE __attribute__((always_inline)) SHZ_INLINE
135 //! Prevents GCC from inlining the given function.
136# define SHZ_NO_INLINE __attribute__((noinline))
137 //! Forces GCC to inline all calls to other functions made within the tagged function.
138# define SHZ_FLATTEN __attribute__((flatten))
139 //! Tells GCC not to introduce any extra padding for the given type.
140# define SHZ_PACKED __attribute__((packed))
141 //! Tells GCC the function has no effects other than returning a value that depends on its arguments and global variables.
142# define SHZ_PURE __attribute__((pure))
143 //! Tells GCC the function has no effects other than returning a value that depends only on its arguments.
144# define SHZ_CONST __attribute__((const))
145 //! Tells GCC that the decorated pointer may be breaking strict aliasing rules for C and C++
146# define SHZ_ALIASING __attribute__((__may_alias__))
147 //! Tells GCC that the expression is likely to be true (used for conditional and loop optimizations)
148# define SHZ_LIKELY(e) __builtin_expect(!!(e), 1)
149 //! Tells GCC that the expression is likely to be false (used for conditional and loop optimizations)
150# define SHZ_UNLIKELY(e) __builtin_expect(!!(e), 0)
151 //! Tells GCC to use its builtin intrinsic for prefetching (better instruction scheduling than pure ASM pref)
152# define SHZ_PREFETCH(a) __builtin_prefetch(a)
153 //! Tells GCC the pointer paraemter is unique and is not aliased by another parameter
154# define SHZ_RESTRICT __restrict__
155 //! Creates a software memory barrier beyond which any loads or stores may not be reordered
156# define SHZ_MEMORY_BARRIER_SOFT() asm volatile("" : : : "memory")
157 //! Creates a hardware memory barrier beyond which any loads or stores may not be reordered
158# define SHZ_MEMORY_BARRIER_HARD() __sync_synchronize()
159#elif defined(SHZ_MSVC)
160 //! Forces a function or type to be aligned by \p N bytes.
161# define SHZ_ALIGNAS(N) __declspec(align(N))
162 //! Unsupported by MSVC.
163# define SHZ_SIMD(N)
164 //! Unsupported by MSVC.
165# define SHZ_HOT
166 //! Unsupported by MSVC.
167# define SHZ_COLD
168 //! Unsupported by MSVC.
169# define SHZ_FAST_MATH
170 //! Unsupported by MSVC.
171# define SHZ_NO_FAST_MATH
172 //! Unsupported by MSVC.
173# define SHZ_NO_UNROLL_LOOPS
174 //! Unsupported by MSVC.
175# define SHZ_NO_OPTIMIZATION
176 //! Unsupported by MSVC.
177# define SHZ_FUNC_ALIGNAS(N)
178 //! Forces MSVC to inline the given function.
179# define SHZ_FORCE_INLINE __forceinline
180 //! Prevents MSVC from inlining the given function.
181# define SHZ_NO_INLINE __declspec(noinline)
182 //! Unsupported by MSVC.
183# define SHZ_FLATTEN
184 //! Unimplemented for MSVC.
185# define SHZ_PACKED
186 //! Unsupported by MSVC.
187# define SHZ_PURE SHZ_CONST
188 //! Tells MSVC that a function may be evaluated at compile-time.
189# define SHZ_CONST constexpr
190 //! MSVC already doesn't optimize for strict aliasing rules.
191# define SHZ_ALIASING
192 //! Unimplemented for MSVC.
193# define SHZ_LIKELY(e) (e)
194 //! Unimplemented for MSVC.
195# define SHZ_UNLIKELY(e) (e)
196 //! Unimplemented for MSVC.
197# define SHZ_PREFETCH(a)
198 //! Tells MSVC the pointer paraemter is unique and is not aliased by another parameter.
199# define SHZ_RESTRICT __restrict
200 //! Unimplemented for MSVC.
201# define SHZ_MEMORY_BARRIER_SOFT()
202 //! Unimpemented for MSVC.
203# define SHZ_MEMORY_BARRIER_HARD()
204#endif
205
206#ifndef __cplusplus
207 //! Dummy define provided for C++ compatibility
208# define SHZ_DECLS_BEGIN
209 //! Dummy define provided for C++ compatibility
210# define SHZ_DECLS_END
211 //! Requests a function or member to be inlined (nonforcibly) OR to have static linkage.
212# define SHZ_INLINE inline static
213 //! Dummy define provided for C++ compatibility
214# define SHZ_NOEXCEPT
215 //! Temporary struct initialization statement to use within C.
216# define SHZ_INIT(type, ...) ((type){ __VA_ARGS__ })
217 //! Conversion macro for zero-overhead conversions, taking the given \p value to a value of the given \p type.
218# define SHZ_CONVERT(type, value)
219 (((struct {
220 union {
221 typeof(value) from;
222 type to;
223 };
224 static_assert(sizeof(type) == sizeof(value), "SHZ_CONVERT: Cannot convert between types of differing sizes.");
225 }){ (value) }).to)
226#else
227 //! Forces functions declared after this directive to use C linkage.
228# define SHZ_DECLS_BEGIN extern "C" {
229 //! Ends forcing functions to use C linkage.
230# define SHZ_DECLS_END }
231 //! Requests a function or member to be inlined (nonforcibly).
232# define SHZ_INLINE inline
233 //! Tells the compiler that the function does not throw exceptions
234# define SHZ_NOEXCEPT noexcept
235 //! Temporary struct initialization statement to use within C++.
236# define SHZ_INIT(type, ...) (type{ __VA_ARGS__ })
237 //! Conversion macro for zero-overhead conversions that handles pointers/references \p from and \p type.
238# define SHZ_CONVERT(type, from)
239 [&]<typename To, typename V>(V&& value) -> To {
240 using TNR = std::remove_reference_t<To>;
241 using VNR = std::remove_reference_t<V>;
242 if constexpr (std::is_pointer_v<To>) {
243 if constexpr (std::is_pointer_v<VNR>) {
244 return reinterpret_cast<To>(value);
245 } else {
246 return reinterpret_cast<To>(&value);
247 }
248 } else if constexpr (std::is_reference_v<To>) {
249 static_assert(sizeof(VNR) == sizeof(TNR), "SHZ_CONVERT: Cannot convert between types of differing sizes when converting to a reference type.");
250 return reinterpret_cast<To>(value);
251 } else {
252 static_assert(sizeof(VNR) == sizeof(TNR), "SHZ_CONVERT: Cannot convert between types of differing sizes.");
253 return reinterpret_cast<To&>(value);
254 }
255 }.template operator()<type>(from)
256#endif
257//! @}
258//! \endcond
259
260/*! \name TLS Utilities
261 \brief Macros for declaring and managing thread-local variables.
262 @{
263*/
265 //! Declares a TLS variable with disabled model (so not thread-local).
266# define SHZ_TLS_DECL(type, name, ...) static type name = __VA_ARGS__;
267 //! References a TLS variable, with disabled model.
268# define SHZ_TLS_REF(name) (&name)
270# include <threads.h>
271 //! Declares a TLS variable with compiler-driven implicit TLS model.
272# define SHZ_TLS_DECL(type, name, ...) static thread_local type name = __VA_ARGS__;
273 //! References a TLS variable with compiler-driven implicit TLS model.
274# define SHZ_TLS_REF(name) (&name)
276# include <pthread.h>
277# include <stdlib.h>
278 //! Declares a TLS variable using pthread thread-specific data.
279# define SHZ_TLS_DECL(type, name, ...)
280 static pthread_key_t name;
281 static void tls_##name##_init_(void) {
282 int res = pthread_key_create(&name, free);
283 (void)res; assert(!res);
284 }
285 static type* tls_##name##_ref_(void) {
286 static pthread_once_t once_ctrl = PTHREAD_ONCE_INIT;
287 int ret = pthread_once(&once_ctrl, tls_##name##_init_);
288 (void)ret; assert(!ret);
289 type* ptr = pthread_getspecific(name);
290 if(!ptr) {
291 ptr = (type *)malloc(sizeof(type));
292 assert(ptr);
293 type temp = __VA_ARGS__;
294 memcpy(ptr, &temp, sizeof(type));
295 ret = pthread_setspecific(name, ptr);
296 assert(!ret);
297 }
298 return ptr;
299 }
300 //! References a TLS variable using pthread thread-specific data.
301# define SHZ_TLS_REF(name) tls_##name##_ref_()
302#elif SHZ_TLS_MODEL == SHZ_TLS_CTHREAD
303# include <threads.h>
304# include <stdlib.h>
305 //! Declares a TLS variable using C11 thread-specific storage.
306# define SHZ_TLS_DECL(type, name, ...)
307 static tss_t name;
308 static void tls_##name##_init_(void) {
309 int res = tss_create(&name, free);
310 (void)res; assert(res == thrd_success);
311 }
312 static type* tls_##name##_ref_(void) {
313 static once_flag once_ctrl = ONCE_FLAG_INIT;
314 call_once(&once_ctrl, tls_##name##_init_);
315 type* ptr = (type *)tss_get(name);
316 if(!ptr) {
317 ptr = (type *)malloc(sizeof(type));
318 assert(ptr);
319 type temp = __VA_ARGS__;
320 memcpy(ptr, &temp, sizeof(type));
321 int res = tss_set(name, ptr);
322 (void)res; assert(res == thrd_success);
323 }
324 return ptr;
325 }
326 //! References a TLS variable using C11 thread-specific storage.
327# define SHZ_TLS_REF(name) tls_##name##_ref_()
328#endif
329//! @}
330
331/*! \name Aliasing Types
332 * \brief Types which may break C/C++'s strict aliasing rules
333 * @{
334 */
335//! int16_t type whose value may be aliased as another type.
336typedef SHZ_ALIASING int16_t shz_alias_int16_t;
337//! uint16_t type whose value may be aliased as another type.
338typedef SHZ_ALIASING uint16_t shz_alias_uint16_t;
339//! int32_t type whose value may be aliased as another type.
340typedef SHZ_ALIASING int32_t shz_alias_int32_t;
341//! uint32_t type whose value may be aliased as another type.
342typedef SHZ_ALIASING uint32_t shz_alias_uint32_t;
343//! float type whose value may be aliased as another type.
344typedef SHZ_ALIASING float shz_alias_float_t;
345//! int64_t type whose value may be aliased as another type.
346typedef SHZ_ALIASING int64_t shz_alias_int64_t;
347//! uint64_t type whose value may be aliased as another type.
348typedef SHZ_ALIASING uint64_t shz_alias_uint64_t;
349//! double type whose value may be aliased as another type.
350typedef SHZ_ALIASING double shz_alias_double_t;
351//! @}
352
353#endif // SHZ_CDEFS_H
#define SHZ_SH4
Back-end for the Dreamcast's SH4.
Definition shz_cdefs.h:30
SHZ_ALIASING int16_t shz_alias_int16_t
int16_t type whose value may be aliased as another type.
Definition shz_cdefs.h:336
SHZ_ALIASING double shz_alias_double_t
double type whose value may be aliased as another type.
Definition shz_cdefs.h:350
#define SHZ_TLS_IMPLICIT
Use thread_local keyword for TLS.
Definition shz_cdefs.h:53
SHZ_ALIASING uint32_t shz_alias_uint32_t
uint32_t type whose value may be aliased as another type.
Definition shz_cdefs.h:342
#define SHZ_SW
Generic C-based software back-end.
Definition shz_cdefs.h:36
#define SHZ_STRINGIFY_LITERAL(a)
Stringifies a literal expression.
Definition shz_cdefs.h:94
#define SHZ_TLS_MODEL
Definition shz_cdefs.h:61
SHZ_ALIASING int64_t shz_alias_int64_t
int64_t type whose value may be aliased as another type.
Definition shz_cdefs.h:346
SHZ_ALIASING uint16_t shz_alias_uint16_t
uint16_t type whose value may be aliased as another type.
Definition shz_cdefs.h:338
SHZ_ALIASING int32_t shz_alias_int32_t
int32_t type whose value may be aliased as another type.
Definition shz_cdefs.h:340
SHZ_ALIASING uint64_t shz_alias_uint64_t
uint64_t type whose value may be aliased as another type.
Definition shz_cdefs.h:348
SHZ_ALIASING float shz_alias_float_t
float type whose value may be aliased as another type.
Definition shz_cdefs.h:344
#define SHZ_BACKEND
Definition shz_cdefs.h:44
#define SHZ_GNUC
Definition shz_cdefs.h:85
#define SHZ_TLS_PTHREAD
Use pthread unique keys for TLS.
Definition shz_cdefs.h:54
#define SHZ_TLS_DISABLED
No thread-local variables.
Definition shz_cdefs.h:52