Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_Extension.H
Go to the documentation of this file.
1#ifndef AMREX_EXTENSION_H_
2#define AMREX_EXTENSION_H_
3#include <AMReX_Config.H>
4
10#if defined(__INTEL_COMPILER) || (defined(__INTEL_LLVM_COMPILER) && !defined(SYCL_LANGUAGE_VERSION))
11#define AMREX_CXX_INTEL
12#elif defined(_CRAYC) || defined(__cray__)
13#define AMREX_CXX_CRAY
14#elif defined(__PGI)
15#define AMREX_CXX_PGI
16#elif defined(__NVCOMPILER)
17#define AMREX_CXX_NVHPC
18#elif defined(__NEC__)
19#define AMREX_CXX_NEC
20#elif defined(__ibmxl__)
21#define AMREX_CXX_IBM
22#elif defined(__clang__)
23#define AMREX_CXX_CLANG
24#elif defined(__GNUC__)
25#define AMREX_CXX_GCC
26#endif
27
28#if !defined(BL_LANG_FORT)
29
30// restrict
31
32#ifdef __cplusplus
33
34#ifdef _WIN32
35#define AMREX_RESTRICT __restrict
36#else
37#define AMREX_RESTRICT __restrict__
38#endif
39
40#else
41
42#define AMREX_RESTRICT restrict
43
44#endif
45
46// simd
47
48#if defined(AMREX_DEBUG)
49#define AMREX_PRAGMA_SIMD
50
51#elif defined(__CUDA_ARCH__) && defined(AMREX_USE_CUDA)
52#define AMREX_PRAGMA_SIMD
53
54#elif defined(__HIP_DEVICE_COMPILE__) && defined(AMREX_USE_HIP)
55#define AMREX_PRAGMA_SIMD
56
57//#elif defined(AMREX_USE_OMP) && defined(_OPENMP) && (_OPENMP >= 201307) && !defined(__PGI)
58//#define AMREX_PRAGMA_SIMD _Pragma("omp simd")
59
60#elif defined(AMREX_CXX_INTEL)
61#define AMREX_PRAGMA_SIMD _Pragma("ivdep")
62
63#elif defined(AMREX_CXX_CRAY)
64#define AMREX_PRAGMA_SIMD _Pragma("ivdep")
65
66#elif defined(AMREX_CXX_PGI)
67#define AMREX_PRAGMA_SIMD _Pragma("loop ivdep")
68
69#elif defined(AMREX_CXX_NVHPC)
70#define AMREX_PRAGMA_SIMD _Pragma("loop ivdep")
71
72#elif defined(AMREX_CXX_NEC)
73#define AMREX_PRAGMA_SIMD
74
75#elif defined(AMREX_CXX_IBM)
76#define AMREX_PRAGMA_SIMD _Pragma("ibm independent_loop")
77
78#elif defined(__clang__)
79#define AMREX_PRAGMA_SIMD
80
81#elif defined(__GNUC__)
82#define AMREX_PRAGMA_SIMD _Pragma("GCC ivdep")
83
84#else
85#define AMREX_PRAGMA_SIMD
86
87#endif /* simd */
88
89// force inline
90#if defined(__CUDA_ARCH__) && defined(AMREX_USE_CUDA)
91#define AMREX_FORCE_INLINE __forceinline__
92
93#elif defined(__HIP_DEVICE_COMPILE__) && defined(AMREX_USE_HIP)
94#define AMREX_FORCE_INLINE __forceinline__
95
96#elif defined(AMREX_CXX_INTEL)
97#define AMREX_FORCE_INLINE inline __attribute__((always_inline))
98
99#elif defined(AMREX_CXX_CRAY)
100#define AMREX_FORCE_INLINE inline
101
102#elif defined(AMREX_CXX_PGI)
103#define AMREX_FORCE_INLINE inline
104
105#elif defined(AMREX_CXX_NVHPC)
106#define AMREX_FORCE_INLINE inline
107
108#elif defined(AMREX_CXX_NEC)
109#define AMREX_FORCE_INLINE inline
110
111#elif defined(AMREX_CXX_IBM)
112#define AMREX_FORCE_INLINE inline __attribute__((always_inline))
113
114#elif defined(__clang__)
115#define AMREX_FORCE_INLINE inline __attribute__((always_inline))
116
117#elif defined(__GNUC__)
118#define AMREX_FORCE_INLINE inline __attribute__((always_inline))
119
120#elif defined(_MSC_VER)
121#define AMREX_FORCE_INLINE inline __forceinline
122
123#else
124#define AMREX_FORCE_INLINE inline
125
126#endif /* force inline */
127
128
129#ifdef AMREX_USE_FORCE_INLINE
130#define AMREX_INLINE AMREX_FORCE_INLINE
131#else
132#define AMREX_INLINE inline
133#endif
134
135// no inline
136#if defined(_MSC_VER)
137#define AMREX_NO_INLINE __declspec(noinline)
138#elif (defined(__GNUC__) || defined(__clang__) || defined(__CUDACC__) || defined(__HIP__) || defined(__INTEL_CLANG_COMPILER))
139#define AMREX_NO_INLINE __attribute__((noinline))
140#else
141#define AMREX_NO_INLINE
142#endif
143
144// flatten
145#if defined(_MSC_VER)
146#define AMREX_FLATTEN [[msvc::flatten]]
147#elif defined(__clang__) || defined(__GNUC__)
148#define AMREX_FLATTEN __attribute__((flatten))
149#else
150#define AMREX_FLATTEN
151#endif
152
153#ifdef AMREX_USE_FLATTEN_FOR
154#define AMREX_ATTRIBUTE_FLATTEN_FOR AMREX_FLATTEN
155#else
156#define AMREX_ATTRIBUTE_FLATTEN_FOR
157#endif
158
159// unroll loop
160#define AMREX_TO_STRING_HELPER(X) #X
161#define AMREX_TO_STRING(X) AMREX_TO_STRING_HELPER(X)
162
163#if defined(__clang__) || defined(__CUDACC__) || defined(__HIP__) || defined(__INTEL_CLANG_COMPILER)
164#define AMREX_UNROLL_LOOP(n) _Pragma(AMREX_TO_STRING(unroll n))
165#elif defined(__GNUC__)
166#define AMREX_UNROLL_LOOP(n) _Pragma(AMREX_TO_STRING(GCC unroll n))
167#else
168#define AMREX_UNROLL_LOOP(n)
169#endif
170
171// __COUNTER__
172//
173// __COUNTER__ has been a de-facto extension in all compilers AMReX supports for
174// a very long time, but it was only recently adopted into C2y. Clang 22 and
175// later therefore diagnose it as a C2y extension under -Wpedantic, even in C++
176// (https://github.com/llvm/llvm-project/issues/196557). Bracket a use of
177// __COUNTER__ with these macros to silence that diagnostic. The nested
178// -Wunknown-warning-option suppression keeps older Clang, which does not know
179// -Wc2y-extensions, quiet as well.
180//
181// Each AMREX_WARNING_PUSH_* macro silences a specific diagnostic, while the
182// single AMREX_WARNING_POP restores the previous state of whatever was pushed
183// last. The naming is intentionally asymmetric: the pops are not tied to a
184// particular warning, so pushes and pops must nest, not interleave.
185
186#if defined(__clang__)
187#define AMREX_WARNING_PUSH_COUNTER \
188 _Pragma("clang diagnostic push") \
189 _Pragma("clang diagnostic ignored \"-Wunknown-warning-option\"") \
190 _Pragma("clang diagnostic ignored \"-Wc2y-extensions\"")
191#define AMREX_WARNING_POP \
192 _Pragma("clang diagnostic pop")
193#else
194#define AMREX_WARNING_PUSH_COUNTER
195#define AMREX_WARNING_POP
196#endif
197
198// __attribute__((weak))
199
200#if defined(AMREX_TYPECHECK)
201#define AMREX_ATTRIBUTE_WEAK
202#elif defined(_WIN32)
203#define AMREX_ATTRIBUTE_WEAK
204#elif defined(__clang__) && defined(__apple_build_version__)
205#define AMREX_ATTRIBUTE_WEAK __attribute__((weak_import))
206#else
207#define AMREX_ATTRIBUTE_WEAK __attribute__((weak))
208#endif
209
210// public globals
211// https://stackoverflow.com/questions/54560832/cmake-windows-export-all-symbols-does-not-cover-global-variables/54568678#54568678
212#if defined(_MSC_VER)
213# if defined(AMREX_IS_DLL)
214# if defined(AMREX_IS_DLL_BUILDING)
215# define AMREX_EXPORT __declspec(dllexport)
216# else
217# define AMREX_EXPORT __declspec(dllimport)
218# endif
219# else
220# define AMREX_EXPORT
221# endif
222#else
223# define AMREX_EXPORT
224#endif
225
226#if defined(__cplusplus) && defined(_WIN32)
227#include <ciso646>
228#endif
229
230#if defined(__INTEL_COMPILER) && defined(__EDG__) && (__cplusplus < 201703L)
231// Classical EDG based Intel compiler does not support fallthrough when std=c++14
232# define AMREX_FALLTHROUGH ((void)0)
233#elif defined(__has_cpp_attribute) && __has_cpp_attribute(fallthrough) >= 201603L
234# define AMREX_FALLTHROUGH [[fallthrough]]
235#elif defined(__clang__)
236# define AMREX_FALLTHROUGH [[clang::fallthrough]]
237#elif defined(__GNUC__) && (__GNUC__ >= 7)
238# define AMREX_FALLTHROUGH [[gnu::fallthrough]]
239#else
240# define AMREX_FALLTHROUGH ((void)0)
241#endif
242
243// Note: following compilers support [[likely]] and [[unlikely]]
244// - Clang >= 12.0
245// - GCC >= 9.0
246// - Intel >= 2021.7
247// - MSVC >= 19.26
248// - nvcc >= 12
249#if defined(__has_cpp_attribute) && __has_cpp_attribute(likely) >= 201803L
250# define AMREX_LIKELY [[likely]]
251# define AMREX_UNLIKELY [[unlikely]]
252#else
253# define AMREX_LIKELY
254# define AMREX_UNLIKELY
255#endif
256
257// Note: following compilers support assumptions, at least using builtin functions:
258// - Clang >= 3.7
259// - GCC >= 5.1
260// - MSVC >= 19.20
261// - nvcc >= 11.1.0
262// - icx >= 2021.1.2
263//
264// [[assume]] itself is C++23. Clang >= 19 and GCC >= 13 advertise it through
265// __has_cpp_attribute in older language modes as well, and Clang then diagnoses
266// every use as a C++23 extension under -Wpedantic
267// (-Wc++23-attribute-extensions). So only take the attribute when the language
268// mode really is C++23 and rely on the compiler-specific spellings below
269// otherwise; they carry the same information to the optimizer.
270#if defined(__has_cpp_attribute) && __has_cpp_attribute(assume) >= 202207L && \
271 defined(__cplusplus) && __cplusplus >= 202302L
272# define AMREX_ASSUME(ASSUMPTION) [[assume(ASSUMPTION)]]
273#else
274# if defined(__CUDA_ARCH__) && defined(__CUDACC__)
275# define AMREX_ASSUME(ASSUMPTION) __builtin_assume(ASSUMPTION)
276# elif defined(AMREX_CXX_INTEL) || defined(__clang__)
277# define AMREX_ASSUME(ASSUMPTION) __builtin_assume(ASSUMPTION)
278# elif defined(_MSC_VER)
279# define AMREX_ASSUME(ASSUMPTION) __assume(ASSUMPTION)
280# elif defined(__GNUC__) && __GNUC__ >= 13
281 // like [[assume]], this does not evaluate ASSUMPTION
282# define AMREX_ASSUME(ASSUMPTION) __attribute__((assume(ASSUMPTION)))
283# elif defined(__GNUC__)
284# define AMREX_ASSUME(ASSUMPTION) \
285 do { if (!(ASSUMPTION)) { __builtin_unreachable(); } } while (0)
286# else
287# define AMREX_ASSUME(ASSUMPTION)
288# endif
289#endif
290
291// CI uses -Werror -Wc++17-extension, thus we need to add the __cplusplus clause
292#if !defined(AMREX_NO_NODISCARD) && defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard) >= 201603L
293# define AMREX_NODISCARD [[nodiscard]]
294#else
295# define AMREX_NODISCARD
296#endif
297
298// Note: following compilers support [[no_unique_address]]
299// - Clang >= 9.0
300// - GCC >= 9.0
301// - MSVC >= 19.26
302// Using no unique address makes empty base class optimization for multiple policies much easier
303#if !defined(AMREX_NO_NO_UNIQUE_ADDRESS) && defined(__has_cpp_attribute) && __has_cpp_attribute(no_unique_address) >= 201803L
304# define AMREX_NO_UNIQUE_ADDRESS [[no_unique_address]]
305# define AMREX_HAS_NO_UNIQUE_ADDRESS 1
306#else
307# define AMREX_NO_UNIQUE_ADDRESS
308#endif
309
310#if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
311# define AMREX_IF_CONSTEXPR if constexpr
312#else
313# define AMREX_IF_CONSTEXPR if
314#endif
315
316#endif /* !BL_LANG_FORT */
317
318#endif