Monado OpenXR Runtime
Loading...
Searching...
No Matches
xrt_compiler.h
Go to the documentation of this file.
1// Copyright 2019, Collabora, Ltd.
2// Copyright 2025-2026, NVIDIA CORPORATION.
3// SPDX-License-Identifier: BSL-1.0
4/*!
5 * @file
6 * @brief Header holding common defines.
7 * @author Jakob Bornecrantz <jakob@collabora.com>
8 * @ingroup xrt_iface
9 */
10
11#pragma once
12
13
14/*
15 * C99 is not a high bar to reach.
16 */
17#include <stddef.h>
18#include <stdint.h>
19#include <stdbool.h>
20#include <inttypes.h>
21
22#ifdef _MSC_VER
23#include <intrin.h>
24// for atomic intrinsics
25#include "xrt_windows.h"
26// Older MSVC versions do not have stdalign.h, define it manually using __declspec(align).
27#define XRT_ALIGNAS(n) __declspec(align(n))
28#elif defined(XRT_DOXYGEN)
29#define XRT_ALIGNAS(align)
30#else // _MSC_VER
31#include <stdalign.h>
32#define XRT_ALIGNAS(align) alignas(align)
33#endif
34
35#if (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN) || \
36 (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
37 (defined(__STDC_ENDIAN_NATIVE__) && __STDC_ENDIAN_NATIVE__ == __STDC_ENDIAN_BIG__) || defined(__BIG_ENDIAN__) || \
38 defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || defined(_MIBSEB) || defined(__MIBSEB) || \
39 defined(__MIBSEB__)
40
41#define XRT_BIG_ENDIAN
42
43#elif (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
44 (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
45 (defined(__STDC_ENDIAN_NATIVE__) && __STDC_ENDIAN_NATIVE__ == __STDC_ENDIAN_LITTLE__) || \
46 defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
47 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || defined(__x86_64__) || defined(_M_X64) || \
48 defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
49
50#undef XRT_BIG_ENDIAN
51
52#else
53#error "@todo: Unable to determine current architecture."
54#endif
55
56/*!
57 * Array size helper.
58 */
59#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
60
61#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_ARCH_PPC64) || defined(__s390x__) || \
62 (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8)
63#define XRT_64_BIT
64#else
65#define XRT_32_BIT
66#endif
67
68/*
69 * Printf helper attribute.
70 */
71#if defined(__GNUC__)
72#define XRT_PRINTF_FORMAT(fmt, list) __attribute__((format(printf, fmt, list)))
73#else
74#define XRT_PRINTF_FORMAT(fmt, list)
75#endif
76
77
78/*
79 * To silence unused warnings.
80 */
81#if defined(__GNUC__)
82#define XRT_MAYBE_UNUSED __attribute__((unused))
83#elif defined(_MSC_VER) && defined(__cplusplus)
84#define XRT_MAYBE_UNUSED [[maybe_unused]]
85#else
86#define XRT_MAYBE_UNUSED
87#endif
88
89
90/*
91 * To indicate that all pointer parameters must not be null.
92 *
93 * Note: MSVC does not have a function-level equivalent. To get similar checking
94 * on MSVC, individual parameters would need SAL annotations like _In_, _Out_, etc.
95 */
96#if defined(__GNUC__)
97#define XRT_NONNULL_ALL __attribute__((nonnull))
98#else
99#define XRT_NONNULL_ALL
100#endif
101
102
103/*
104 * To indicate that the first parameter must not be null.
105 *
106 * Note: MSVC does not have a function-level equivalent. To get similar checking
107 * on MSVC, individual parameters would need SAL annotations like _In_, _Out_, etc.
108 */
109#if defined(__GNUC__)
110#define XRT_NONNULL_FIRST __attribute__((nonnull(1)))
111#else
112#define XRT_NONNULL_FIRST
113#endif
114
115
116/*
117 * To make sure return values are checked.
118 */
119#if defined(__GNUC__) && (__GNUC__ >= 4)
120#define XRT_CHECK_RESULT __attribute__((warn_unused_result))
121#elif defined(_MSC_VER) && (_MSC_VER >= 1700)
122#define XRT_CHECK_RESULT _Check_return_
123#else
124#define XRT_CHECK_RESULT
125#endif
126
127
128/*
129 * To stop inlining.
130 */
131#if defined(__GNUC__)
132#define XRT_NO_INLINE __attribute__((noinline))
133#elif defined(_MSC_VER)
134#define XRT_NO_INLINE __declspec(noinline)
135#else
136#define XRT_NO_INLINE
137#endif
138
139
140#ifdef XRT_DOXYGEN
141/*!
142 * To trigger a trap/break in the debugger.
143 *
144 * @ingroup xrt_iface
145 */
146#define XRT_DEBUGBREAK()
147#elif defined(__clang__) || defined(__GNUC__)
148#define XRT_DEBUGBREAK() __builtin_trap()
149#elif defined(_MSC_VER)
150#define XRT_DEBUGBREAK() __debugbreak()
151#else
152#error "compiler not supported"
153#endif
154
155
156/*
157 * typeof extension, until C23 is widely available. This macro may not always be available,
158 * and should be checked before usage.
159 *
160 * @todo Remove this macro when Monado is updated project-wide to C23.
161 */
162#if __STDC_VERSION__ >= 202311L
163#define XRT_TYPEOF(x) typeof(x)
164#elif defined(__GNUC__) || defined(__clang__)
165#define XRT_TYPEOF(x) __typeof__(x)
166#endif
167
168
169typedef volatile int32_t xrt_atomic_s32_t;
170
171static inline int32_t
172xrt_atomic_s32_inc_return(xrt_atomic_s32_t *p)
173{
174#if defined(__GNUC__)
175 return __sync_add_and_fetch(p, 1);
176#elif defined(_MSC_VER)
177 return InterlockedIncrement((volatile LONG *)p);
178#else
179#error "compiler not supported"
180#endif
181}
182static inline int32_t
183xrt_atomic_s32_dec_return(xrt_atomic_s32_t *p)
184{
185#if defined(__GNUC__)
186 return __sync_sub_and_fetch(p, 1);
187#elif defined(_MSC_VER)
188 return InterlockedDecrement((volatile LONG *)p);
189#else
190#error "compiler not supported"
191#endif
192}
193static inline int32_t
194xrt_atomic_s32_cmpxchg(xrt_atomic_s32_t *p, int32_t old_, int32_t new_)
195{
196#if defined(__GNUC__)
197 return __sync_val_compare_and_swap(p, old_, new_);
198#elif defined(_MSC_VER)
199 return InterlockedCompareExchange((volatile LONG *)p, old_, new_);
200#else
201#error "compiler not supported"
202#endif
203}
204static inline void
205xrt_atomic_s32_store(xrt_atomic_s32_t *p, int32_t v)
206{
207#if defined(__GNUC__)
208 __atomic_store_n(p, v, __ATOMIC_SEQ_CST);
209#elif defined(_MSC_VER)
210 InterlockedExchange((volatile LONG *)p, v);
211#else
212#error "compiler not supported"
213#endif
214}
215static inline int32_t
216xrt_atomic_s32_load(xrt_atomic_s32_t *p)
217{
218#if defined(__GNUC__)
219 return __atomic_load_n(p, __ATOMIC_SEQ_CST);
220#elif defined(_MSC_VER)
221 return InterlockedCompareExchange((volatile LONG *)p, 0, 0);
222#else
223#error "compiler not supported"
224#endif
225}
226
227typedef volatile int64_t xrt_atomic_s64_t;
228
229static inline int64_t
230xrt_atomic_s64_inc_return(xrt_atomic_s64_t *p)
231{
232#if defined(__GNUC__)
233 return __sync_add_and_fetch(p, 1);
234#elif defined(_MSC_VER)
235 return InterlockedIncrement64((volatile LONG64 *)p);
236#else
237#error "compiler not supported"
238#endif
239}
240static inline int64_t
241xrt_atomic_s64_dec_return(xrt_atomic_s64_t *p)
242{
243#if defined(__GNUC__)
244 return __sync_sub_and_fetch(p, 1);
245#elif defined(_MSC_VER)
246 return InterlockedDecrement64((volatile LONG64 *)p);
247#else
248#error "compiler not supported"
249#endif
250}
251static inline int64_t
252xrt_atomic_s64_cmpxchg(xrt_atomic_s64_t *p, int64_t old_, int64_t new_)
253{
254#if defined(__GNUC__)
255 return __sync_val_compare_and_swap(p, old_, new_);
256#elif defined(_MSC_VER)
257 return InterlockedCompareExchange64((volatile LONG64 *)p, old_, new_);
258#else
259#error "compiler not supported"
260#endif
261}
262static inline void
263xrt_atomic_s64_store(xrt_atomic_s64_t *p, int64_t v)
264{
265#if defined(__GNUC__)
266 __atomic_store_n(p, v, __ATOMIC_SEQ_CST);
267#elif defined(_MSC_VER)
268 InterlockedExchange64((volatile LONG64 *)p, v);
269#else
270#error "compiler not supported"
271#endif
272}
273static inline int64_t
274xrt_atomic_s64_load(xrt_atomic_s64_t *p)
275{
276#if defined(__GNUC__)
277 return __atomic_load_n(p, __ATOMIC_SEQ_CST);
278#elif defined(_MSC_VER)
279 return InterlockedCompareExchange64((volatile LONG64 *)p, 0, 0);
280#else
281#error "compiler not supported"
282#endif
283}
284
285#ifdef _MSC_VER
286typedef intptr_t ssize_t;
287#define _SSIZE_T_
288#define _SSIZE_T_DEFINED
289#endif
290
291/*!
292 * Get the holder from a pointer to a field.
293 *
294 * @ingroup xrt_iface
295 */
296#define container_of(ptr, type, field) (type *)((char *)ptr - offsetof(type, field))
297
298
299#ifdef XRT_DOXYGEN
300
301/*!
302 * Very small default init for structs that works in both C and C++. Helps with
303 * code that needs to be compiled with both C and C++.
304 *
305 * @ingroup xrt_iface
306 */
307
308// clang-format off
309#define XRT_STRUCT_INIT {}
310// clang-format on
311
312#elif defined(__cplusplus)
313
314// clang-format off
315#define XRT_STRUCT_INIT {}
316// clang-format on
317
318#else
319
320// clang-format off
321#define XRT_STRUCT_INIT {0}
322// clang-format on
323
324#endif
325
326/*
327 * C11 style designated initializers (as compound literals) causes warning messages
328 * in C++ (even in C++20), usage:
329 *
330 * @code{.c}
331 * static inline struct xrt_foo_bar
332 * xrt_foo_bar_make()
333 * {
334 * return XRT_C11_COMPOUND(struct xrt_foo_bar){
335 * .x = y,
336 * // ...
337 * };
338 * }
339 * @endcode
340 */
341#ifdef __cplusplus
342#define XRT_C11_COMPOUND(X)
343#else
344#define XRT_C11_COMPOUND(X) (X)
345#endif
A minimal way to include Windows.h.