-
Notifications
You must be signed in to change notification settings - Fork 351
/
platform.h
483 lines (415 loc) · 17.2 KB
/
platform.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
// Copyright Contributors to the Open Shading Language project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/imageworks/OpenShadingLanguage
/////////////////////////////////////////////////////////////////////////
// \file
// platform.h is where we put all the platform-specific macros.
// Things like:
//
// * Detecting which compiler is being used.
// * Detecting which C++ standard is being used and what features are
// available.
// * Various helpers that need to be defined differently per compiler,
// language version, OS, etc.
/////////////////////////////////////////////////////////////////////////
// clang-format off
#pragma once
#include <memory>
#include <OSL/oslversion.h>
/////////////////////////////////////////////////////////////////////////
// Detect which compiler and version we're using
// Define OSL_GNUC_VERSION to hold an encoded gcc version (e.g. 40802 for
// 4.8.2), or 0 if not a GCC release. N.B.: This will be 0 for clang.
#if defined(__GNUC__) && !defined(__clang__)
# define OSL_GNUC_VERSION (10000*__GNUC__ + 100*__GNUC_MINOR__ + __GNUC_PATCHLEVEL__)
#else
# define OSL_GNUC_VERSION 0
#endif
// Define OSL_CLANG_VERSION to hold an encoded generic Clang version (e.g.
// 30402 for clang 3.4.2), or 0 if not a generic Clang release.
// N.B. This will be 0 for the clang Apple distributes (which has different
// version numbers entirely).
#if defined(__clang__) && !defined(__apple_build_version__)
# define OSL_CLANG_VERSION (10000*__clang_major__ + 100*__clang_minor__ + __clang_patchlevel__)
#else
# define OSL_CLANG_VERSION 0
#endif
// Define OSL_APPLE_CLANG_VERSION to hold an encoded Apple Clang version
// (e.g. 70002 for clang 7.0.2), or 0 if not an Apple Clang release.
#if defined(__clang__) && defined(__apple_build_version__)
# define OSL_APPLE_CLANG_VERSION (10000*__clang_major__ + 100*__clang_minor__ + __clang_patchlevel__)
#else
# define OSL_APPLE_CLANG_VERSION 0
#endif
// Define OSL_INTEL_COMPILER to hold an encoded Intel compiler version
// (e.g. 1900), or 0 if not an Intel compiler.
#if defined(__INTEL_COMPILER)
# define OSL_INTEL_COMPILER __INTEL_COMPILER
#else
# define OSL_INTEL_COMPILER 0
#endif
// Intel's compiler on OSX may still define __clang__
// and we have need to know when using a true clang compiler
#if !defined(__INTEL_COMPILER) && defined(__clang__)
#define OSL_NON_INTEL_CLANG __clang__
#else
#define OSL_NON_INTEL_CLANG 0
#endif
// Tests for MSVS versions, always 0 if not MSVS at all.
#if defined(_MSC_VER)
# if _MSC_VER < 1900
# error "This version of OSL is meant to work only with Visual Studio 2015 or later"
# endif
# define OSL_MSVS_AT_LEAST_2013 (_MSC_VER >= 1800)
# define OSL_MSVS_BEFORE_2013 (_MSC_VER < 1800)
# define OSL_MSVS_AT_LEAST_2015 (_MSC_VER >= 1900)
# define OSL_MSVS_BEFORE_2015 (_MSC_VER < 1900)
# define OSL_MSVS_AT_LEAST_2017 (_MSC_VER >= 1910)
# define OSL_MSVS_BEFORE_2017 (_MSC_VER < 1910)
#else
# define OSL_MSVS_AT_LEAST_2013 0
# define OSL_MSVS_BEFORE_2013 0
# define OSL_MSVS_AT_LEAST_2015 0
# define OSL_MSVS_BEFORE_2015 0
# define OSL_MSVS_AT_LEAST_2017 0
# define OSL_MSVS_BEFORE_2017 0
#endif
// Note about __CUDACC__ versus __CUDA_ARCH__:
//
// __CUDACC__ defined any time we are compiling a module for Cuda
// (both for the host pass and the device pass). "Do this
// when using nvcc or clang with ptx target."
// __CUDA_ARCH__ is only defined when doing the device pass. "Do this only
// for code that will actually run on the GPU."
/////////////////////////////////////////////////////////////////////////
// Detect which C++ standard we're using, and handy macros.
// See https://en.cppreference.com/w/cpp/compiler_support
//
// Note: oslversion.h defines OSL_BUILD_CPP11 to be 1 if OSL was built
// using C++11. In contrast, OSL_CPLUSPLUS_VERSION defined below will be set
// to the right number for the C++ standard being compiled RIGHT NOW. These
// two things may be the same when compiling OSL, but they may not be the
// same if another package is compiling against OSL and using these headers
// (OSL may be C++11 but the client package may be newer, or vice versa --
// use these two symbols to differentiate these cases, when important).
#if (__cplusplus >= 202001L)
# define OSL_CPLUSPLUS_VERSION 20
# define OSL_CONSTEXPR14 constexpr
# define OSL_CONSTEXPR17 constexpr
# define OSL_CONSTEXPR20 constexpr
#elif (__cplusplus >= 201703L)
# define OSL_CPLUSPLUS_VERSION 17
# define OSL_CONSTEXPR14 constexpr
# define OSL_CONSTEXPR17 constexpr
# define OSL_CONSTEXPR20 /* not constexpr before C++20 */
#elif (__cplusplus >= 201402L) || (defined(_MSC_VER) && _MSC_VER >= 1914)
# define OSL_CPLUSPLUS_VERSION 14
# define OSL_CONSTEXPR14 constexpr
# define OSL_CONSTEXPR17 /* not constexpr before C++17 */
# define OSL_CONSTEXPR20 /* not constexpr before C++20 */
#elif (__cplusplus >= 201103L) || _MSC_VER >= 1900
# define OSL_CPLUSPLUS_VERSION 11
# define OSL_CONSTEXPR14 /* not constexpr before C++14 */
# define OSL_CONSTEXPR17 /* not constexpr before C++17 */
# define OSL_CONSTEXPR20 /* not constexpr before C++20 */
#else
# error "This version of OSL requires C++11"
#endif
// In C++20 (and some compilers before that), __has_cpp_attribute can
// test for understand of [[attr]] tests.
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
// On gcc & clang, __has_attribute can test for __attribute__((attr))
#ifndef __has_attribute
# define __has_attribute(x) 0
#endif
// In C++17 (and some compilers before that), __has_include("blah.h") or
// __has_include(<blah.h>) can test for presence of an include file.
#ifndef __has_include
# define __has_include(x) 0
#endif
/////////////////////////////////////////////////////////////////////////
// Pragmas and attributes that vary per platform
// Generic pragma definition
#if defined(_MSC_VER)
// Of course MS does it in a quirky way
#define OSL_PRAGMA(UnQuotedPragma) __pragma(UnQuotedPragma)
#else
// All other compilers seem to support C99 _Pragma
#define OSL_PRAGMA(UnQuotedPragma) _Pragma(#UnQuotedPragma)
#endif
// Compiler-specific pragmas
#if defined(__GNUC__) /* gcc, clang, icc */
# define OSL_PRAGMA_WARNING_PUSH OSL_PRAGMA(GCC diagnostic push)
# define OSL_PRAGMA_WARNING_POP OSL_PRAGMA(GCC diagnostic pop)
# define OSL_PRAGMA_VISIBILITY_PUSH OSL_PRAGMA(GCC visibility push(default))
# define OSL_PRAGMA_VISIBILITY_POP OSL_PRAGMA(GCC visibility pop)
# define OSL_GCC_PRAGMA(UnQuotedPragma) OSL_PRAGMA(UnQuotedPragma)
# if defined(__clang__)
# define OSL_CLANG_PRAGMA(UnQuotedPragma) OSL_PRAGMA(UnQuotedPragma)
# else
# define OSL_CLANG_PRAGMA(UnQuotedPragma)
# endif
# if defined(__INTEL_COMPILER)
# define OSL_INTEL_PRAGMA(UnQuotedPragma) OSL_PRAGMA(UnQuotedPragma)
# else
# define OSL_INTEL_PRAGMA(UnQuotedPragma)
# endif
# define OSL_MSVS_PRAGMA(UnQuotedPragma)
#elif defined(_MSC_VER)
# define OSL_PRAGMA_WARNING_PUSH __pragma(warning(push))
# define OSL_PRAGMA_WARNING_POP __pragma(warning(pop))
# define OSL_PRAGMA_VISIBILITY_PUSH /* N/A on MSVS */
# define OSL_PRAGMA_VISIBILITY_POP /* N/A on MSVS */
# define OSL_GCC_PRAGMA(UnQuotedPragma)
# define OSL_CLANG_PRAGMA(UnQuotedPragma)
# define OSL_INTEL_PRAGMA(UnQuotedPragma)
# define OSL_MSVS_PRAGMA(UnQuotedPragma) OSL_PRAGMA(UnQuotedPragma)
#else
# define OSL_PRAGMA_WARNING_PUSH
# define OSL_PRAGMA_WARNING_POP
# define OSL_PRAGMA_VISIBILITY_PUSH
# define OSL_PRAGMA_VISIBILITY_POP
# define OSL_GCC_PRAGMA(UnQuotedPragma)
# define OSL_CLANG_PRAGMA(UnQuotedPragma)
# define OSL_INTEL_PRAGMA(UnQuotedPragma)
# define OSL_MSVS_PRAGMA(UnQuotedPragma)
#endif
#ifdef __clang__
#define OSL_CLANG_ATTRIBUTE(value) __attribute__((value))
#else
#define OSL_CLANG_ATTRIBUTE(value)
#endif
#ifndef OSL_DEBUG
#ifdef NDEBUG
#define OSL_DEBUG 0
#else
#ifdef _DEBUG
#define OSL_DEBUG _DEBUG
#else
#define OSL_DEBUG 1
#endif
#endif
#endif // OSL_DEBUG
#if OSL_DEBUG
// Disable OPENMP_SIMD when debugging
#undef OSL_OPENMP_SIMD
#endif
#ifdef OSL_OPENMP_SIMD
#define OSL_OMP_PRAGMA(aUnQuotedPragma) OSL_PRAGMA(aUnQuotedPragma)
#else
#define OSL_OMP_PRAGMA(aUnQuotedPragma)
#endif
// OSL_FORCEINLINE is a function attribute that attempts to make the
// function always inline. On many compilers regular 'inline' is only
// advisory. Put this attribute before the function return type, just like
// you would use 'inline'. Note that if OSL_DEBUG is true, it just becomes
// ordinary inline.
#if OSL_DEBUG
# define OSL_FORCEINLINE inline
#elif defined(__CUDACC__)
# define OSL_FORCEINLINE __inline__
#elif defined(__GNUC__) || defined(__clang__) || __has_attribute(always_inline)
# define OSL_FORCEINLINE inline __attribute__((always_inline))
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
# define OSL_FORCEINLINE __forceinline
#else
# define OSL_FORCEINLINE inline
#endif
// OSL_NOINLINE hints to the compiler that the functions should never be
// inlined.
#if defined(__GNUC__) || defined(__clang__) || __has_attribute(noinline)
# define OSL_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
# define OSL_NOINLINE __declspec(noinline)
#else
# define OSL_NOINLINE
#endif
// OSL_FORCEINLINE_BLOCK tells the compiler that any calls in the next
// statement (or compound statement/code block)should be inlined whenever
// the compiler is capable of doing so. Furthermore, any calls made by those
// calls should be inlined, and so on recursively. Has no affect on function calls to
// whose definition exists in different translation units or calls that are not
// legal to inline (possibly by OSL_NOINLINE). Intent is to ensure that entire
// contents of a SIMD loop body is are fully inlined avoiding compiler heuristics.
// However if any debugging code exists inside the code block, then the amount
// of code inlined could explode. So great care should be used when placing
// code inside one of these forced inline blocks. Note that if OSL_DEBUG is true,
// it does nothing to avoid over-inlining.
// NOTE: only supported by Intel C++ compiler.
// Unsupported compilers may instead use command line flags to increase their inlining
// limits/thresholds
#if OSL_DEBUG
#define OSL_FORCEINLINE_BLOCK
#else
#define OSL_FORCEINLINE_BLOCK OSL_INTEL_PRAGMA(forceinline recursive)
#endif
// OSL_MAYBE_UNUSED is a function or variable attribute that assures the
// compiler that it's fine for the item to appear to be unused.
#if OSL_CPLUSPLUS_VERSION >= 17 || __has_cpp_attribute(maybe_unused)
# define OSL_MAYBE_UNUSED [[maybe_unused]]
#elif defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) || __has_attribute(unused)
# define OSL_MAYBE_UNUSED __attribute__((unused))
#else
# define OSL_MAYBE_UNUSED
#endif
// Some compilers define a special intrinsic to use in conditionals that can
// speed up extremely performance-critical spots if the conditional is
// usually (or rarely) is true. You use it by replacing
// if (x) ...
// with
// if (OSL_LIKELY(x)) ... // if you think x will usually be true
// or
// if (OSL_UNLIKELY(x)) ... // if you think x will rarely be true
// Caveat: Programmers are notoriously bad at guessing this, so it
// should be used only with thorough benchmarking.
#if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)
# define OSL_LIKELY(x) (__builtin_expect(bool(x), true))
# define OSL_UNLIKELY(x) (__builtin_expect(bool(x), false))
#else
# define OSL_LIKELY(x) (x)
# define OSL_UNLIKELY(x) (x)
#endif
#ifndef OSL_HOSTDEVICE
# ifdef __CUDACC__
# define OSL_HOSTDEVICE __host__ __device__
# else
# define OSL_HOSTDEVICE
# endif
#endif
#ifndef OSL_DEVICE
# ifdef __CUDACC__
# define OSL_DEVICE __device__
# else
# define OSL_DEVICE
# endif
#endif
#ifndef OSL_CONSTANT_DATA
# ifdef __CUDACC__
# define OSL_CONSTANT_DATA __constant__
# else
# define OSL_CONSTANT_DATA
# endif
#endif
// OSL_DEPRECATED before a function declaration marks it as deprecated in
// a way that will generate compile warnings if it is called (but will
// preserve linkage compatibility).
#if OSL_CPLUSPLUS_VERSION >= 14 || __has_cpp_attribute(deprecated)
# define OSL_DEPRECATED(msg) [[deprecated(msg)]]
#elif defined(__GNUC__) || defined(__clang__) || __has_attribute(deprecated)
# define OSL_DEPRECATED(msg) __attribute__((deprecated(msg)))
#elif defined(_MSC_VER)
# define OSL_DEPRECATED(msg) __declspec(deprecated(msg))
#else
# define OSL_DEPRECATED(msg)
#endif
// OSL_FALLTHROUGH at the end of a `case` label's statements documents that
// the switch statement case is intentionally falling through to the code for
// the next case.
#if OSL_CPLUSPLUS_VERSION >= 17 || __has_cpp_attribute(fallthrough)
# define OSL_FALLTHROUGH [[fallthrough]]
#else
# define OSL_FALLTHROUGH
#endif
// OSL_NODISCARD following a function declaration documents that the
// function's return value should never be ignored.
#if OSL_CPLUSPLUS_VERSION >= 17 || __has_cpp_attribute(nodiscard)
# define OSL_NODISCARD [[nodiscard]]
#else
# define OSL_NODISCARD
#endif
/// Work around bug in GCC with mixed __attribute__ and alignas parsing
/// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69585
#ifdef __GNUC__
# define OSL_ALIGNAS(size) __attribute__((aligned(size)))
#else
# define OSL_ALIGNAS(size) alignas(size)
#endif
// OSL_PRETTY_FUNCTION gives a text string of the current function
// declaration.
#if defined(__PRETTY_FUNCTION__)
# define OSL_PRETTY_FUNCTION __PRETTY_FUNCTION__ /* gcc, clang */
#elif defined(__FUNCSIG__)
# define OSL_PRETTY_FUNCTION __FUNCSIG__ /* MS gotta be different */
#else
# define OSL_PRETTY_FUNCTION __FUNCTION__
#endif
/// OSL_ABORT_IF_DEBUG is a call to abort() for debug builds, but does
/// nothing for release builds.
#ifndef NDEBUG
# define OSL_ABORT_IF_DEBUG abort()
#else
# define OSL_ABORT_IF_DEBUG (void)0
#endif
/// OSL_ASSERT(condition) checks if the condition is met, and if not,
/// prints an error message indicating the module and line where the error
/// occurred, and additionally aborts if in debug mode. When in release
/// mode, it prints the error message if the condition fails, but does not
/// abort.
///
/// OSL_ASSERT_MSG(condition,msg,...) lets you add formatted output (a la
/// printf) to the failure message.
#ifndef __CUDA_ARCH__
# define OSL_ASSERT_PRINT(...) (std::fprintf(stderr, __VA_ARGS__))
#else
# define OSL_ASSERT_PRINT(...) (printf(__VA_ARGS__))
#endif
#define OSL_ASSERT(x) \
(OSL_LIKELY(x) \
? ((void)0) \
: (OSL_ASSERT_PRINT("%s:%u: %s: Assertion '%s' failed.\n", \
__FILE__, __LINE__, OSL_PRETTY_FUNCTION, #x), \
OSL_ABORT_IF_DEBUG))
#define OSL_ASSERT_MSG(x, msg, ...) \
(OSL_LIKELY(x) \
? ((void)0) \
: (std::fprintf(stderr, "%s:%u: %s: Assertion '%s' failed: " msg "\n", \
__FILE__, __LINE__, OSL_PRETTY_FUNCTION, #x, \
__VA_ARGS__), \
OSL_ABORT_IF_DEBUG))
/// OSL_DASSERT and OSL_DASSERT_MSG are the same as OSL_ASSERT for debug
/// builds (test, print error, abort), but do nothing at all in release
/// builds (not even perform the test). This is similar to C/C++ assert(),
/// but gives us flexibility in improving our error messages. It is also ok
/// to use regular assert() for this purpose if you need to eliminate the
/// dependency on this header from a particular place (and don't mind that
/// assert won't format identically on all platforms).
#ifndef NDEBUG
# define OSL_DASSERT OSL_ASSERT
# define OSL_DASSERT_MSG OSL_ASSERT_MSG
#else
# define OSL_DASSERT(x) ((void)sizeof(x)) /*NOLINT*/
# define OSL_DASSERT_MSG(x, ...) ((void)sizeof(x)) /*NOLINT*/
#endif
OSL_NAMESPACE_ENTER
#if OSL_CPLUSPLUS_VERSION >= 20
using std::assume_aligned;
#else
// Until we have c++20, we can provide our own version of std::assume_aligned
// http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1007r0.pdf
template<int Alignment, class DataT>
OSL_NODISCARD
#ifndef __INTEL_COMPILER // constexpr not compatible with ICC's __assume_aligned
constexpr
#endif
DataT* assume_aligned(DataT* ptr)
{
#ifdef __INTEL_COMPILER
__assume_aligned(ptr, Alignment);
return ptr;
#elif defined(__clang__) || defined(__GNUC__)
return reinterpret_cast<DataT*>(__builtin_assume_aligned(ptr, Alignment));
#elif defined(_MSC_VER)
constexpr std::uintptr_t unaligned_bit_mask = (Alignment - 1);
if ((reinterpret_cast<std::uintptr_t>(ptr) & unaligned_bit_mask) == 0)
return ptr;
else
__assume(0); // let compiler know we should never reach this branch
#else
#error unknown compiler, update assume_aligned to handle (or explicitly ignore) emitting a pointer alignment hint
return ptr;
#endif
}
#endif
OSL_NAMESPACE_EXIT