SuperDex Physics C++ API
Loading...
Searching...
No Matches
mochi_platform.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**************************************************************************************************
18 This header declares macros which depend on the current platform, compiler, or CPU
19 features. See mochi_config.h for additional macros which enable/disable optional features.
20*/
21
22// no #pragma once for pure C inclusion
23#ifndef MOCHI_PLATFORM_H
24#define MOCHI_PLATFORM_H
25
26#if defined(__cplusplus)
27#include <type_traits>
28#endif
29
30/**************************************************************************************************
31 Language:
32 - MOCHI_LANGUAGE_CPP Compiling with a C++ compiler (any version)
33 - MOCHI_LANGUAGE_CPP17 Compiling with a C++ compiler that supports C++17 (or newer)
34 - MOCHI_LANGUAGE_CPP20 Compiling with a C++ compiler that supports C++20 (or newer)
35 - MOCHI_LANGUAGE_C Compiling with a C compiler
36*/
37#if defined(__cplusplus)
38#define MOCHI_LANGUAGE_CPP 1
39#define MOCHI_LANGUAGE_CPP17 (__cplusplus >= 201703L)
40#ifndef MOCHI_LANGUAGE_CPP20 // Can be defined to 0 in build script to test C++17 fallbacks.
41#define MOCHI_LANGUAGE_CPP20 (__cplusplus >= 202002L)
42#endif
43#define MOCHI_LANGUAGE_C 0
44#else
45#define MOCHI_LANGUAGE_CPP 0
46#define MOCHI_LANGUAGE_CPP17 0
47#ifndef MOCHI_LANGUAGE_CPP20
48#define MOCHI_LANGUAGE_CPP20 0
49#endif
50#define MOCHI_LANGUAGE_C 1
51#endif
52
53/**************************************************************************************************
54 Architecture:
55 - MOCHI_ARCH_CPU Compiling for CPU (regular CPU code or CUDA CPU host)
56 - MOCHI_ARCH_GPU Compiling for GPU (CUDA GPU device code)
57 - MOCHI_ARCH_ARM Compiling for an ARM CPU (64-bit ARMv8 or newer)
58 - MOCHI_ARCH_ARM_NEON Compiling for an ARM CPU with NEON (mandatory for ARMv8 or newer)
59 - MOCHI_ARCH_ARM_NEON_FP16_ARITHMETIC
60 Compiling with the ARM FP16 vector arithmetic feature enabled
61 - MOCHI_ARCH_ARM_SVE Compiling for an ARM CPU with SVE (mandatory for ARMv9 or newer)
62 - MOCHI_ARCH_ARM_SME Compiling for an ARM CPU with SME (scalable matrix extension)
63 - MOCHI_ARCH_X64 Compiling for an x64 CPU (64-bit x86, also called x86_64)
64 - MOCHI_ARCH_X64_AVX512 Compiling for an x64 CPU with AVX-512 F, CD, BW, DQ, and VL
65 - MOCHI_ARCH_X64_AVX2 Compiling for an x64 CPU with AVX2 vector extension
66 - MOCHI_ARCH_X64_FMA Compiling for an x64 CPU with FMA (fused multiply add) extension
67 - MOCHI_ARCH_X64_SVML Compiling for an x64 CPU with SVML (small vector math library) extension
68*/
69#if defined(__CUDA_ARCH__)
70#define MOCHI_ARCH_CPU 0
71#define MOCHI_ARCH_GPU 1
72#else
73#define MOCHI_ARCH_CPU 1
74#define MOCHI_ARCH_GPU 0
75#endif
76
77// NOTE: The Unreal Engine build system has its own macros.
78#if defined(PLATFORM_ENABLE_VECTORINTRINSICS_NEON) && PLATFORM_ENABLE_VECTORINTRINSICS_NEON
79#define MOCHI_UNREAL_ARCH_NEON 1
80#else
81#define MOCHI_UNREAL_ARCH_NEON 0
82#endif
83
84#if defined(__aarch64__) || MOCHI_UNREAL_ARCH_NEON
85#define MOCHI_ARCH_ARM 1
86#else
87#define MOCHI_ARCH_ARM 0
88#endif
89
90#if MOCHI_ARCH_CPU && MOCHI_ARCH_ARM && (defined(__ARM_NEON) || MOCHI_UNREAL_ARCH_NEON)
91#define MOCHI_ARCH_ARM_NEON 1
92#else
93#define MOCHI_ARCH_ARM_NEON 0
94#endif
95
96#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
97#define MOCHI_ARCH_ARM_NEON_FP16_ARITHMETIC 1
98#else
99#define MOCHI_ARCH_ARM_NEON_FP16_ARITHMETIC 0
100#endif
101
102// NOTE: The Unreal Engine build system has its own macros.
103#define MOCHI_UNREAL_ARCH_AVX2 0
104
105#if defined(PLATFORM_CPU_X86_FAMILY)
106#if PLATFORM_CPU_X86_FAMILY
107#undef MOCHI_UNREAL_ARCH_AVX2
108#define MOCHI_UNREAL_ARCH_AVX2 1 // Assume AVX2 for Unreal Engine builds
109#endif
110#endif
111
112// UNREALIOS_LINUX_EDITOR disables AVX2 for the Linux editor build.
113// The editor target shares its PCH with UnrealEditor, which is compiled without -mavx2.
114// Adding -mavx2 per-module causes a PCH/AST feature mismatch.
115// Game target does use AVX2.
116#if defined(UNREALIOS_LINUX_EDITOR)
117#if UNREALIOS_LINUX_EDITOR
118#undef MOCHI_UNREAL_ARCH_AVX2
119#define MOCHI_UNREAL_ARCH_AVX2 0
120#endif
121#endif
122
123#if defined(_M_X64) || defined(__x86_64) || MOCHI_UNREAL_ARCH_AVX2
124#define MOCHI_ARCH_X64 1
125#else
126#define MOCHI_ARCH_X64 0
127#endif
128
129#if MOCHI_ARCH_CPU && MOCHI_ARCH_X64 && defined(__AVX512F__) && defined(__AVX512CD__) && \
130 defined(__AVX512BW__) && defined(__AVX512DQ__) && defined(__AVX512VL__)
131#define MOCHI_ARCH_X64_AVX512 1
132#else
133#define MOCHI_ARCH_X64_AVX512 0
134#endif
135
136#if MOCHI_ARCH_CPU && MOCHI_ARCH_X64 && \
137 (MOCHI_ARCH_X64_AVX512 || defined(__AVX2__) || MOCHI_UNREAL_ARCH_AVX2)
138#define MOCHI_ARCH_X64_AVX2 1
139#else
140#define MOCHI_ARCH_X64_AVX2 0
141#endif
142
143#if MOCHI_ARCH_CPU && MOCHI_ARCH_X64_AVX2 && \
144 (defined(__FMA__) || (defined(_MSC_VER) && !defined(__clang__)))
145#define MOCHI_ARCH_X64_FMA 1
146#else
147#define MOCHI_ARCH_X64_FMA 0
148#endif
149
150#if MOCHI_ARCH_CPU && MOCHI_ARCH_X64_AVX2 && \
151 (defined(__SVML__) || (defined(_MSC_VER) && !defined(__clang__)))
152#define MOCHI_ARCH_X64_SVML 1
153#else
154#define MOCHI_ARCH_X64_SVML 0
155#endif
156
157// Error checking
158#if !MOCHI_ARCH_ARM && (defined(__arm__) || defined(_M_ARM))
159#error Mochi does not support older 32-bit versions of ARM
160#endif
161#if MOCHI_ARCH_ARM && MOCHI_ARCH_X64
162#error Failed to detect correct architecture
163#endif
164#if MOCHI_UNREAL_ARCH_AVX2 && MOCHI_UNREAL_ARCH_NEON
165#error Cannot have both AVX and NEON
166#endif
167
168/**************************************************************************************************
169 Compiler:
170 - MOCHI_COMPILER_MSVC Microsoft Visual C++ (MSVC)
171 - MOCHI_COMPILER_GCC GNU C/C++ compiler
172 - MOCHI_COMPILER_CLANG CLANG C/C++ compiler
173 - MOCHI_COMPILER_CUDA_CPU CUDA compiler (NVCC) compiling a .cu file for the CPU.
174 - MOCHI_COMPILER_CUDA_GPU CUDA compiler (NVCC) compiling a .cu file for the GPU.
175 - MOCHI_COMPILER_CUDA CUDA compiler (NVCC) compiling a .cu file for CPU or GPU.
176
177 NOTE:
178 When compiling a .cu file, (MOCHI_COMPILER_CUDA && MOCHI_COMPILER_CLANG) can both be true
179 because NVCC uses the host compiler (e.g. clang) to preprocess the file. If the host compiler
180 was GCC or MSVC, then MOCHI_COMPILER_GCC or MOCHI_COMPILER_MSVC would be true while compiling
181 that .cu file.
182*/
183
184#if defined(_MSC_VER) && !defined(__clang__)
185// NOTE: Both _MSC_VER and __clang__ are defined when the Clang frontend targets the MSVC
186// backend (clang-cl). The code which uses MOCHI_COMPILER_MSVC only cares about the frontend
187// (e.g. C++ warnings, minor differences in xmmintrin.h, etc...)
188#define MOCHI_COMPILER_MSVC 1
189#else
190#define MOCHI_COMPILER_MSVC 0
191#endif
192
193// MOCHI_MSVC_TRADITIONAL indicates that MSVC is doing its old non-standard compliant behavior.
194// You can make it more standard compliant (less "traditional"), but it is not the default.
195#if defined(_MSVC_TRADITIONAL)
196#define MOCHI_MSVC_TRADITIONAL _MSVC_TRADITIONAL
197#else
198#define MOCHI_MSVC_TRADITIONAL 0
199#endif
200
201#if defined(__GNUC__) && !defined(__clang__)
202#define MOCHI_COMPILER_GCC 1
203#else
204#define MOCHI_COMPILER_GCC 0
205#endif
206#if defined(__clang__)
207#define MOCHI_COMPILER_CLANG 1
208#if (__clang_major__ < 19)
209#define MOCHI_CLANG_AWAIT_SUSPEND_BUG 1
210#else
211#define MOCHI_CLANG_AWAIT_SUSPEND_BUG 0
212#endif
213#else
214#define MOCHI_COMPILER_CLANG 0
215#define MOCHI_CLANG_AWAIT_SUSPEND_BUG 0
216#endif
217
218#if defined(__CUDA_ARCH__) // CUDA GPU
219#define MOCHI_COMPILER_CUDA_CPU 0
220#define MOCHI_COMPILER_CUDA_GPU 1
221#define MOCHI_COMPILER_CUDA 1
222#elif defined(__CUDACC__) // CUDA CPU
223#define MOCHI_COMPILER_CUDA_CPU 1
224#define MOCHI_COMPILER_CUDA_GPU 0
225#define MOCHI_COMPILER_CUDA 1
226#else // Neither
227#define MOCHI_COMPILER_CUDA_CPU 0
228#define MOCHI_COMPILER_CUDA_GPU 0
229#define MOCHI_COMPILER_CUDA 0
230#endif
231
232// Sanitizers
233#if defined(__SANITIZE_ADDRESS__) && (MOCHI_COMPILER_CLANG || MOCHI_COMPILER_GCC)
234#define MOCHI_COMPILER_ASAN 1
235#else
236#define MOCHI_COMPILER_ASAN 0
237#endif
238#if defined(__SANITIZE_THREAD__) && (MOCHI_COMPILER_CLANG || MOCHI_COMPILER_GCC)
239#define MOCHI_COMPILER_TSAN 1
240#else
241#define MOCHI_COMPILER_TSAN 0
242#endif
243#if (MOCHI_COMPILER_CLANG || MOCHI_COMPILER_GCC)
244#if defined(__has_feature)
245#if __has_feature(address_sanitizer)
246#undef MOCHI_COMPILER_ASAN
247#define MOCHI_COMPILER_ASAN 1
248#endif
249#endif
250#if defined(__has_feature)
251#if __has_feature(thread_sanitizer)
252#undef MOCHI_COMPILER_TSAN
253#define MOCHI_COMPILER_TSAN 1
254#endif
255#endif
256#endif
257
258#if MOCHI_COMPILER_CLANG
259#if __has_feature(cxx_rtti)
260#define MOCHI_COMPILER_HAS_RTTI 1
261#else
262#define MOCHI_COMPILER_HAS_RTTI 0
263#endif
264#elif MOCHI_COMPILER_GCC
265#ifdef __GXX_RTTI
266#define MOCHI_COMPILER_HAS_RTTI 1
267#else
268#define MOCHI_COMPILER_HAS_RTTI 0
269#endif
270#elif MOCHI_COMPILER_MSVC
271#ifdef _CPPRTTI
272#define MOCHI_COMPILER_HAS_RTTI 1
273#else
274#define MOCHI_COMPILER_HAS_RTTI 0
275#endif
276#else
277// RTTI is assumed to be enabled on other compilers.
278// If not, then add a check here.
279#define MOCHI_COMPILER_HAS_RTTI 1
280#endif
281
282/**************************************************************************************************
283 MOCHI_HAS_VA_OPT indicates whether or not __VA_OPT__ is supported.
284*/
285#define MOCHI_HAS_VA_OPT (MOCHI_LANGUAGE_CPP20 && !MOCHI_MSVC_TRADITIONAL)
286
287/**************************************************************************************************
288 Platform:
289 - MOCHI_PLATFORM_ANDROID Compiling for Android.
290 - MOCHI_PLATFORM_LINUX Compiling for Linux (not including Android)
291 - MOCHI_PLATFORM_MACOS Compiling for MacOS.
292 - MOCHI_PLATFORM_WINDOWS Compiling for Windows.
293
294*/
295#if defined(__ANDROID__)
296#define MOCHI_PLATFORM_ANDROID 1
297#else
298#define MOCHI_PLATFORM_ANDROID 0
299#endif
300
301#if defined(__linux__) && !defined(__ANDROID__)
302#define MOCHI_PLATFORM_LINUX 1
303#else
304#define MOCHI_PLATFORM_LINUX 0
305#endif
306
307#if defined(__APPLE__)
308#define MOCHI_PLATFORM_MACOS 1
309#else
310#define MOCHI_PLATFORM_MACOS 0
311#endif
312
313#if defined(_WIN32)
314#define MOCHI_PLATFORM_WINDOWS 1
315#else
316#define MOCHI_PLATFORM_WINDOWS 0
317#endif
318
319/**************************************************************************************************
320 CUDA Function Attributes:
321 - MOCHI_ANY Function can run on host or device
322 - MOCHI_CPU Function can only run on CPU host
323 - MOCHI_GPU Function can only run on GPU device
324 - MOCHI_GPU_KERNEL Function is a "global" GPU kernel
325*/
326#if MOCHI_COMPILER_CUDA
327#define MOCHI_ANY __host__ __device__
328#define MOCHI_CPU __host__
329#define MOCHI_GPU __device__
330#define MOCHI_GPU_KERNEL __global__
331#else
332#define MOCHI_ANY
333#define MOCHI_CPU
334#define MOCHI_GPU
335#define MOCHI_GPU_KERNEL
336#endif
337
338/**************************************************************************************************
339 MOCHI_FORCE_INLINE
340 A stronger version of 'inline'. Ignored in Debug configuration.
341 WARNING: Only use this on small functions to avoid code bloat.
342
343 Example:
344 MOCHI_FORCE_INLINE void Foo() {}
345*/
346#ifdef NDEBUG
347// NOTE: Order matters because MOCHI_COMPILER_* macros may not be mutually exclusive. Check CUDA GPU
348// first.
349#if MOCHI_COMPILER_CUDA_GPU
350#define MOCHI_FORCE_INLINE __forceinline__
351#elif MOCHI_COMPILER_MSVC
352#define MOCHI_FORCE_INLINE __forceinline
353#else
354#define MOCHI_FORCE_INLINE __attribute__((always_inline)) inline
355#endif
356#else
357#define MOCHI_FORCE_INLINE inline
358#endif
359
360/**************************************************************************************************
361 MOCHI_FORCE_INLINE_LAMBDA
362 A stronger version of 'inline' for a lambda's call operator (operator()): directs the compiler
363 to inline the lambda body into its call sites.
364
365 WARNING: Only use on small lambdas in hot paths (avoids code bloat).
366
367 NOTE: Only effective for *direct* calls through the concrete closure type (e.g. the lambda held
368 by 'auto' or passed as a template parameter). If the lambda is type-erased into an std::function
369 (or called via function pointer / virtual dispatch), the call is indirect and the body is NOT
370 inlined at that boundary.
371
372 Example:
373 auto foo = [](int x) MOCHI_FORCE_INLINE_LAMBDA { return x + 1; };
374*/
375#ifdef NDEBUG
376// NOTE: Order matters because MOCHI_COMPILER_* macros may not be mutually exclusive. Check CUDA GPU
377// first.
378#if MOCHI_COMPILER_CUDA_GPU
379#define MOCHI_FORCE_INLINE_LAMBDA
380#elif (MOCHI_COMPILER_CLANG || MOCHI_COMPILER_GCC)
381#define MOCHI_FORCE_INLINE_LAMBDA __attribute__((always_inline))
382#else
383#if defined(__has_cpp_attribute)
384#if __has_cpp_attribute(msvc::forceinline)
385#define MOCHI_FORCE_INLINE_LAMBDA [[msvc::forceinline]]
386#else
387#define MOCHI_FORCE_INLINE_LAMBDA
388#endif // #if __has_cpp_attribute(msvc::forceinline)
389#else
390#define MOCHI_FORCE_INLINE_LAMBDA
391#endif // #if defined(__has_cpp_attribute)
392#endif // #if MOCHI_COMPILER_CUDA_GPU
393#else
394#define MOCHI_FORCE_INLINE_LAMBDA
395#endif // #ifdef NDEBUG
396
397/**************************************************************************************************
398 MOCHI_UNROLL_LOOP_N
399 Requests that the compiler unroll the immediately following loop by N.
400
401 NOTE: This is a best-effort hint. The compiler may ignore it. It expands to nothing on MSVC and on
402 unrecognized compilers.
403
404 Example:
405 MOCHI_UNROLL_LOOP_N(4)
406 for (int i = 0; i < 4; ++i) {}
407*/
408// NOTE: Order matters because MOCHI_COMPILER_* macros may not be mutually exclusive. Check CUDA GPU
409// first.
410#if MOCHI_COMPILER_CUDA_GPU
411#define MOCHI_UNROLL_LOOP_N(N) _Pragma(MOCHI_PP_STRINGIFY(unroll N))
412#elif MOCHI_COMPILER_MSVC
413#define MOCHI_UNROLL_LOOP_N(N)
414#elif MOCHI_COMPILER_GCC
415#define MOCHI_UNROLL_LOOP_N(N) _Pragma(MOCHI_PP_STRINGIFY(GCC unroll N))
416#elif MOCHI_COMPILER_CLANG
417#define MOCHI_UNROLL_LOOP_N(N) _Pragma(MOCHI_PP_STRINGIFY(unroll N))
418#else
419#define MOCHI_UNROLL_LOOP_N(N)
420#endif
421
422/**************************************************************************************************
423 MOCHI_NO_INLINE
424 Directs the compiler NOT to inline a function.
425
426 Example:
427 MOCHI_NO_INLINE void Foo() {}
428*/
429#if MOCHI_COMPILER_CUDA_GPU
430#define MOCHI_NO_INLINE __noinline__
431#elif MOCHI_COMPILER_MSVC
432#define MOCHI_NO_INLINE __declspec(noinline)
433#else
434#define MOCHI_NO_INLINE __attribute__((noinline))
435#endif
436
437/**************************************************************************************************
438 MOCHI_RESTRICT
439 Qualifies a pointer argument as restricted, promising to the compiler that
440 the memory accessed via the pointer will not be aliased by any other pointer.
441 This enables some compiler optimizations.
442
443 Example:
444 void MyCopy(float* MOCHI_RESTRICT dst, float const* MOCHI_RESTRICT src, size_t n) {
445 memcpy(dst, src, n);
446 }
447*/
448// NOTE: Order matters because MOCHI_COMPILER_* macros may not be mutually exclusive.
449#if MOCHI_COMPILER_CUDA_GPU || MOCHI_COMPILER_GCC || MOCHI_COMPILER_CLANG
450#define MOCHI_RESTRICT __restrict__
451#elif MOCHI_COMPILER_MSVC
452#define MOCHI_RESTRICT __restrict
453#else
454#define MOCHI_RESTRICT restrict
455#endif
456
457/**************************************************************************************************
458 SIMD:
459 MOCHI_SIMD_REGISTER_COUNT Number of floating-point SIMD registers.
460 MOCHI_SIMD_REGISTER_SIZE_BYTES Size (in bytes) of each floating-point SIMD register.
461*/
462#if MOCHI_ARCH_X64_AVX512
463#define MOCHI_SIMD_REGISTER_COUNT 32
464#define MOCHI_SIMD_REGISTER_SIZE_BYTES 64
465#elif MOCHI_ARCH_X64_AVX2
466#define MOCHI_SIMD_REGISTER_COUNT 16
467#define MOCHI_SIMD_REGISTER_SIZE_BYTES 32
468#elif MOCHI_ARCH_ARM_NEON
469#define MOCHI_SIMD_REGISTER_COUNT 32
470#define MOCHI_SIMD_REGISTER_SIZE_BYTES 16
471#else
472#define MOCHI_SIMD_REGISTER_COUNT Unsupported architecture
473#define MOCHI_SIMD_REGISTER_SIZE_BYTES Unsupported architecture
474#endif
475
476/**************************************************************************************************
477 Memory Cache
478*/
479
480/**
481 * @brief Conservative upper limit for the size (and alignment) of a data cache line.
482 *
483 * @details Cache line size is a property of the CPU, so it is not known at compile time.
484 * This conservative value can be used when compile-time alignment is needed. For a more
485 * accurate runtime value use @ref GetCacheLineInfo.
486 *
487 * @see MOCHI_CONSERVATIVE_CACHE_ALIGN, GetCacheLineInfo
488 */
489#ifndef MOCHI_CONSERVATIVE_CACHE_LINE_SIZE
490#define MOCHI_CONSERVATIVE_CACHE_LINE_SIZE 256
491#endif
492
493/**
494 * @brief Aligns the memory of a variable so it starts at the beginning of a cache line.
495 *
496 * @details Cache line size is a property of the CPU, so it is not known at compile time. This
497 * conservative value will waste some memory on most systems, but that is usually acceptable for
498 * static variables and temporary variables.
499 *
500 * @see MOCHI_CONSERVATIVE_CACHE_LINE_SIZE, GetCacheLineInfo
501 */
502#define MOCHI_CONSERVATIVE_CACHE_ALIGN alignas(MOCHI_CONSERVATIVE_CACHE_LINE_SIZE)
503
504/**************************************************************************************************
505 MOCHI_NO_INIT
506 Add this attribute to the end of a non-static local variable declaration to tell the compiler
507 that it should NOT be initialized to zero. Without the attribute, clang/gcc will sometimes
508 perform the initialization even though the programmer did not request it.
509
510 Example:
511 std::byte buffer0[4096] MOCHI_NO_INIT, buffer1[1024] MOCHI_NO_INIT;
512*/
513#if MOCHI_COMPILER_GCC || MOCHI_COMPILER_CLANG
514// clang-format off
515#define MOCHI_NO_INIT __attribute__((uninitialized)) /* NOLINT(cppcoreguidelines-init-variables) */
516// clang-format on
517#else
518#define MOCHI_NO_INIT /* NOLINT(cppcoreguidelines-init-variables) */
519#endif
520
521/**************************************************************************************************
522 MOCHI_DEBUG_BREAK()
523 Trigger a debug breakpoint (fatal if no debugger is connected)
524*/
525// NOTE: Order matters because MOCHI_COMPILER_* macros may not be mutually exclusive. Check CUDA GPU
526// first.
527#if MOCHI_COMPILER_CUDA_GPU
528#define MOCHI_DEBUG_BREAK() asm("brkpt;")
529#elif MOCHI_PLATFORM_WINDOWS
530#define MOCHI_DEBUG_BREAK() __debugbreak()
531#else
532#define MOCHI_DEBUG_BREAK() __builtin_trap()
533#endif
534
535/**************************************************************************************************
536 Warning Suppression:
537 Use these macros if you really need to suppress a specific compiler warning.
538 Targeted suppression is better than global suppression.
539
540 GCC and Clang:
541 Clang is able to understand GCC's warning suppression syntax and they support many of the same
542 warnings. Therefore, we often use the GCC warning suppression syntax for both via
543 MOCHI_WARNING_IGNORE_GCC_CLANG. GCC and Clang both require you to specify the full argument
544 string because _Pragma does not support string literal concatenation.
545
546 Examples:
547 MOCHI_WARNING_PUSH();
548 MOCHI_WARNING_IGNORE_MSVC(4100);
549 MOCHI_WARNING_IGNORE_GCC_CLANG(GCC diagnostic ignored "-Wunused-parameter");
550 MOCHI_WARNING_IGNORE_CLANG(clang diagnostic ignored "-Wself-assign-overloaded");
551 // YOUR CODE HERE
552 MOCHI_WARNING_POP();
553*/
554// NOTE: Order matters because MOCHI_COMPILER_* macros may not be mutually exclusive. Check CUDA GPU
555// first.
556#if MOCHI_COMPILER_CUDA_GPU
557#define MOCHI_WARNING_PUSH()
558#define MOCHI_WARNING_PUSH_IGNORE_ALL()
559#define MOCHI_WARNING_POP()
560#elif MOCHI_COMPILER_MSVC
561#define MOCHI_WARNING_PUSH() __pragma(warning(push))
562#define MOCHI_WARNING_PUSH_IGNORE_ALL() __pragma(warning(push, 0))
563#define MOCHI_WARNING_POP() __pragma(warning(pop))
564#elif MOCHI_COMPILER_CLANG
565#define MOCHI_WARNING_PUSH() _Pragma("GCC diagnostic push")
566#define MOCHI_WARNING_PUSH_IGNORE_ALL() \
567 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Weverything\"")
568#define MOCHI_WARNING_POP() _Pragma("GCC diagnostic pop")
569#elif MOCHI_COMPILER_GCC
570#define MOCHI_WARNING_PUSH() _Pragma("GCC diagnostic push")
571#define MOCHI_WARNING_PUSH_IGNORE_ALL() \
572 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wall\"") \
573 _Pragma("GCC diagnostic ignored \"-Wextra\"")
574#define MOCHI_WARNING_POP() _Pragma("GCC diagnostic pop")
575#else
576#define MOCHI_WARNING_PUSH()
577#define MOCHI_WARNING_PUSH_IGNORE_ALL()
578#define MOCHI_WARNING_POP()
579#endif
580
581#if MOCHI_COMPILER_MSVC
582#define MOCHI_WARNING_IGNORE_MSVC(X) __pragma(warning(disable : X))
583#define MOCHI_WARNING_ENFORCE_MSVC(X) __pragma(warning(error : X))
584#else
585#define MOCHI_WARNING_IGNORE_MSVC(X)
586#define MOCHI_WARNING_ENFORCE_MSVC(X)
587#endif
588
589#if MOCHI_COMPILER_GCC
590#define MOCHI_WARNING_IGNORE_GCC(X) _Pragma(#X)
591#define MOCHI_WARNING_ENFORCE_GCC(X) _Pragma(#X)
592#else
593#define MOCHI_WARNING_IGNORE_GCC(X)
594#define MOCHI_WARNING_ENFORCE_GCC(X)
595#endif
596
597#if MOCHI_COMPILER_CLANG
598#define MOCHI_WARNING_IGNORE_CLANG(X) _Pragma(#X)
599#define MOCHI_WARNING_ENFORCE_CLANG(X) _Pragma(#X)
600#else
601#define MOCHI_WARNING_IGNORE_CLANG(X)
602#define MOCHI_WARNING_ENFORCE_CLANG(X)
603#endif
604
605// Macros for warnings that are supported by both GCC and Clang
606#if MOCHI_COMPILER_GCC || MOCHI_COMPILER_CLANG
607#define MOCHI_WARNING_IGNORE_GCC_CLANG(X) _Pragma(#X)
608#define MOCHI_WARNING_ENFORCE_GCC_CLANG(X) _Pragma(#X)
609#else
610#define MOCHI_WARNING_IGNORE_GCC_CLANG(X)
611#define MOCHI_WARNING_ENFORCE_GCC_CLANG(X)
612#endif
613
614// Opt-ins for compiler specific warnings that are off by default.
615// These warnings are enabled in every supported build.
616/* Data member 'member1' will be initialized after data member 'member2' */
618
619// Opt-outs for other warnings.
620/* function marked as __forceinline not inlined */
622
623/**************************************************************************************************
624 Warning Suppression for CUDA
625*/
626
627#if MOCHI_COMPILER_CUDA
628#define MOCHI_WARNING_IGNORE_CUDA(X) __pragma(diag_suppress = X)
629#define MOCHI_WARNING_ENFORCE_CUDA(X) __pragma(diag_error = X)
630#else
631#define MOCHI_WARNING_IGNORE_CUDA(X)
632#define MOCHI_WARNING_ENFORCE_CUDA(X)
633#endif
634
635// Edge case: some templated utility functions may be instantiated using CPU-only
636// functions, which will result in a warning from NVCC. In such cases, it is
637// necessary to disable this check (until a better solution is found...)
638#if MOCHI_COMPILER_CUDA_GPU
639#if __CUDAVER__ >= 75000
640#define MOCHI_DISABLE_CUDA_GPU_EXEC_CHECK() __pragma(nv_exec_check_disable)
641#else
642#define MOCHI_DISABLE_CUDA_GPU_EXEC_CHECK()
643#endif
644#else
645#define MOCHI_DISABLE_CUDA_GPU_EXEC_CHECK()
646#endif
647
648#define MOCHI_TEMPLATE_FUNCTION MOCHI_DISABLE_CUDA_GPU_EXEC_CHECK()
649
650// Opt-outs for compiler-specific warnings for third-party libraries or
651// other exotic compilers (NVCC). Most of these are unavoidable, so we
652// have to wrap inclusion locations with these directives.
653#define MOCHI_WARNING_SUPPRESS_CUDA() \
654 /* Nonstandard extension used : nameless struct */ \
655 MOCHI_WARNING_IGNORE_MSVC(4201) \
656 /* '=' : conversion from 'OffsetT' to 'int', possible loss of data */ \
657 MOCHI_WARNING_IGNORE_MSVC(4244) \
658 /* Structure was padded due to alignment specifier */ \
659 MOCHI_WARNING_IGNORE_MSVC(4324) \
660 /* Declaration of 'variable' hides class member */ \
661 MOCHI_WARNING_IGNORE_MSVC(4458) \
662 /* Unreferenced local function has been removed */ \
663 MOCHI_WARNING_IGNORE_MSVC(4505) \
664 /* Uninitalized local variable */ \
665 MOCHI_WARNING_IGNORE_MSVC(4700) \
666 /* Assignment within conditional expression */ \
667 MOCHI_WARNING_IGNORE_MSVC(4706) \
668 /* Spurious "missing return statement at end of non-void function" \
669 in constexpr functions. Fixed in later versions of CUDA (>11.1). */ \
670 MOCHI_WARNING_IGNORE_CUDA(implicit_return_from_non_void_function)
671
672/**************************************************************************************************
673 Warning Suppression for Eigen
674*/
676#define MOCHI_WARNING_SUPPRESS_EIGEN() \
677 /* Conditional expression is constant */ \
678 MOCHI_WARNING_IGNORE_MSVC(4127) \
679 /* Check operator precedence for possible error; use parentheses to clarify precedence */ \
680 MOCHI_WARNING_IGNORE_MSVC(4554) \
681 /* Conversion from '__int64' to 'uint64_t', signed/unsigned mismatch */ \
682 MOCHI_WARNING_IGNORE_MSVC(4245) \
683 /* annotation ignored on a function that is explicitly defaulted */ \
684 MOCHI_WARNING_IGNORE_CUDA(esa_on_defaulted_function_ignored)
685
686/**************************************************************************************************
687 Runtime Checks Suppression
688 Some third party headers (e.g. thrust) trigger MSVC's run-time checks when ran
689 with Debug configuration. While these errors are mostly harmless, they are
690 terribly cumbersome. These macros allow us to selectively suppress these checks.
691*/
692#if MOCHI_COMPILER_MSVC
693#define MOCHI_DEBUG_RTCHECKS_ENABLE() __pragma(runtime_checks("sc", restore))
694#define MOCHI_DEBUG_RTCHECKS_DISABLE() __pragma(runtime_checks("sc", off))
695#else
696#define MOCHI_DEBUG_RTCHECKS_ENABLE()
697#define MOCHI_DEBUG_RTCHECKS_DISABLE()
698#endif
699
700/**************************************************************************************************
701 No-Op
702*/
703
704#if MOCHI_COMPILER_MSVC
705#include <intrin.h>
706#define MOCHI_NOP() __nop();
707#else
708#define MOCHI_NOP() __asm__ __volatile__("nop");
709#endif
710// clang-format off
711#define MOCHI_NOP_10() \
712 MOCHI_NOP(); MOCHI_NOP(); MOCHI_NOP(); MOCHI_NOP(); MOCHI_NOP(); \
713 MOCHI_NOP(); MOCHI_NOP(); MOCHI_NOP(); MOCHI_NOP(); MOCHI_NOP();
714#define MOCHI_NOP_50() \
715 MOCHI_NOP_10(); MOCHI_NOP_10(); MOCHI_NOP_10(); MOCHI_NOP_10(); MOCHI_NOP_10();
716#define MOCHI_NOP_250() \
717 MOCHI_NOP_50(); MOCHI_NOP_50(); MOCHI_NOP_50(); MOCHI_NOP_50(); MOCHI_NOP_50();
718// clang-format on
719
720/**************************************************************************************************
721 Pre-processor Helpers
722*/
723
724// Pre-processor concatenation, for use in other macros.
725#define MOCHI_PP_CAT(a, b) MOCHI_PP_CAT_IMPL(a, b)
726#define MOCHI_PP_CAT_IMPL(a, b) a##b
727
728// Pre-processor stringization, for use in other macros (e.g. _Pragma operands).
729#define MOCHI_PP_STRINGIFY(X) MOCHI_PP_STRINGIFY_IMPL(X)
730#define MOCHI_PP_STRINGIFY_IMPL(X) #X
731
732/**************************************************************************************************
733 Move & Copy Semantics
734*/
735
736// Declares default move operations. Goes inside a class or struct declaration.
737#define MOCHI_DECLARE_MOVE(Name) \
738 Name(Name&&) noexcept = default; \
739 Name& operator=(Name&&) = default;
740
741// Deletes the default move operations. Goes inside a class or struct declaration.
742#define MOCHI_DECLARE_NO_MOVE(Name) \
743 Name(Name&&) = delete; \
744 Name& operator=(Name&&) = delete;
745
746// Declares default copy operations. Goes inside a class or struct declaration.
747// Can be used in private scope to enable an explicit Copy() function.
748#define MOCHI_DECLARE_COPY(Name) \
749 Name(Name const&) = default; \
750 Name& operator=(Name const&) = default;
751
752// Deletes the default copy operations. Goes inside a class or struct declaration.
753#define MOCHI_DECLARE_NO_COPY(Name) \
754 Name(Name const&) = delete; \
755 Name& operator=(Name const&) = delete;
756
757// Deletes both the copy and move operations. Goes inside a class or struct declaration.
758// Note that "pinned" is a term borrowed from other languages. It means the address of the object
759// is not allowed to change.
760#define MOCHI_DECLARE_NO_COPY_NO_MOVE(Name) \
761 MOCHI_DECLARE_NO_COPY(Name) \
762 MOCHI_DECLARE_NO_MOVE(Name)
763
764// Declares unique ownership semantics (move but no copy). Goes inside a class or struct
765// declaration.
766#define MOCHI_DECLARE_MOVE_ONLY(Name) \
767 MOCHI_DECLARE_MOVE(Name); \
768 MOCHI_DECLARE_NO_COPY(Name)
769
770// Declares the default copy constructor and move constructor, but deletes assignment.
771// Used for classes/structs containing view matrices, which cannot be copied via operator= (because
772// that would copy values instead).
773#define MOCHI_DECLARE_NO_ASSIGN(Name) \
774 Name& operator=(Name const&) = delete; \
775 Name& operator=(Name&&) = delete;
776
777// Declares of class with inheritance from an empty base to activate EBCO
778// (Empty Base Class Optimization)
779#if MOCHI_COMPILER_MSVC
780#define MOCHI_EMPTY_BASE __declspec(empty_bases)
781#else
782#define MOCHI_EMPTY_BASE
783#endif
784
785/**************************************************************************************************
786 Concepts
787*/
788
789#if MOCHI_LANGUAGE_CPP
790// A unique type used in MOCHI_CONCEPT macros. Does not allow implicit conversions from other types.
791namespace superdex {
792enum class ConceptMatch { True };
793} // namespace superdex
794#endif // MOCHI_LANGUAGE_CPP
795
796// Use this in function declarations that would 'requires' a type trait. Similar to C++20 concepts.
797//
798// Example:
799//
800// // This function only matches overload resolution for arithmetic types
801// template <typename T, MOCHI_CONCEPT(std::is_arithmetic_v<T>)>
802// void Foo(T value);
804#define MOCHI_CONCEPT(a) std::enable_if_t<a, superdex::ConceptMatch> = superdex::ConceptMatch::True
805
806// Use this in function definitions where the declaration is elsewhere.
807#define MOCHI_CONCEPT_DEF(a) std::enable_if_t<a, superdex::ConceptMatch>
808
809/**************************************************************************************************
810 Branch Prediction Hints
811
812 Examples:
813 if (condition) MOCHI_LIKELY {} // Hint: This branch will probably be taken
814 if (condition) MOCHI_UNLIKELY {} // Hint: This branch will probably NOT be taken.
815*/
816#if MOCHI_LANGUAGE_CPP20
817#define MOCHI_LIKELY [[likely]]
818#define MOCHI_UNLIKELY [[unlikely]]
819#else
820#define MOCHI_LIKELY
821#define MOCHI_UNLIKELY
822#endif
823
824/**************************************************************************************************
825 Validation of the above macros
826*/
827
828#if !(MOCHI_COMPILER_CUDA || MOCHI_COMPILER_MSVC || MOCHI_COMPILER_GCC || MOCHI_COMPILER_CLANG)
829#error "Unknown compiler"
830#endif
831#if !( \
832 MOCHI_PLATFORM_ANDROID || MOCHI_PLATFORM_LINUX || MOCHI_PLATFORM_MACOS || \
833 MOCHI_PLATFORM_WINDOWS)
834#error "Unknown platform"
835#endif
836
837#endif // MOCHI_PLATFORM_H
#define MOCHI_WARNING_IGNORE_MSVC(X)
#define MOCHI_WARNING_ENFORCE_MSVC(X)