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