-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathplatform.hpp
306 lines (269 loc) · 9.8 KB
/
platform.hpp
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
#ifndef LIBASSERT_PLATFORM_HPP
#define LIBASSERT_PLATFORM_HPP
// Copyright (c) 2021-2024 Jeremy Rifkin under the MIT license
// https://github.com/jeremy-rifkin/libassert
// =====================================================================================================================
// || Preprocessor stuff ||
// =====================================================================================================================
// Set the C++ version number based on if we are on a dumb compiler like MSVC or not.
#ifdef _MSVC_LANG
#define LIBASSERT_CPLUSPLUS _MSVC_LANG
#else
#define LIBASSERT_CPLUSPLUS __cplusplus
#endif
#if LIBASSERT_CPLUSPLUS < 201703L
#error "libassert requires C++17 or newer"
#endif
#if LIBASSERT_CPLUSPLUS >= 202302L
#define LIBASSERT_STD_VER 23
#elif LIBASSERT_CPLUSPLUS >= 202002L
#define LIBASSERT_STD_VER 20
#elif LIBASSERT_CPLUSPLUS >= 201703L
#define LIBASSERT_STD_VER 17
#else
#error "Can't happen"
#endif
///
/// Detect compiler versions.
///
#if defined(__clang__) && !defined(__ibmxl__)
#define LIBASSERT_IS_CLANG 1
#define LIBASSERT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
#else
#define LIBASSERT_IS_CLANG 0
#define LIBASSERT_CLANG_VERSION 0
#endif
#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) && !defined(__INTEL_COMPILER)
#define LIBASSERT_IS_GCC 1
#define LIBASSERT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#else
#define LIBASSERT_IS_GCC 0
#define LIBASSERT_GCC_VERSION 0
#endif
#ifdef _MSC_VER
#define LIBASSERT_IS_MSVC 1
#define LIBASSERT_MSVC_VERSION _MSC_VER
#else
#define LIBASSERT_IS_MSVC 0
#define LIBASSERT_MSVC_VERSION 0
#endif
#ifdef __INTEL_COMPILER
#define LIBASSERT_IS_ICC 1
#else
#define LIBASSERT_IS_ICC 0
#endif
#ifdef __INTEL_LLVM_COMPILER
#define LIBASSERT_IS_ICX 1
#else
#define LIBASSERT_IS_ICX 0
#endif
///
/// Detect standard library versions.
///
// libstdc++
#ifdef _GLIBCXX_RELEASE
#define LIBASSERT_GLIBCXX_RELEASE _GLIBCXX_RELEASE
#else
#define LIBASSERT_GLIBCXX_RELEASE 0
#endif
#ifdef _LIBCPP_VERSION
#define LIBASSERT_LIBCPP_VERSION _LIBCPP_VERSION
#else
#define LIBASSERT_LIBCPP_VERSION 0
#endif
///
/// Helper macros for compiler attributes.
///
#ifdef __has_cpp_attribute
#define LIBASSERT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#define LIBASSERT_HAS_CPP_ATTRIBUTE(x) 0
#endif
///
/// Compiler attribute support.
///
#if LIBASSERT_HAS_CPP_ATTRIBUTE(nodiscard) && LIBASSERT_STD_VER >= 20
#define LIBASSERT_ATTR_NODISCARD_MSG(msg) [[nodiscard(msg)]]
#else // Assume we have normal C++17 nodiscard support.
#define LIBASSERT_ATTR_NODISCARD_MSG(msg) [[nodiscard]]
#endif
#if LIBASSERT_HAS_CPP_ATTRIBUTE(no_unique_address)
#define LIBASSERT_ATTR_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define LIBASSERT_ATTR_NO_UNIQUE_ADDRESS
#endif
///
/// General project macros
///
#ifdef _WIN32
#define LIBASSERT_EXPORT_ATTR __declspec(dllexport)
#define LIBASSERT_IMPORT_ATTR __declspec(dllimport)
#else
#define LIBASSERT_EXPORT_ATTR __attribute__((visibility("default")))
#define LIBASSERT_IMPORT_ATTR __attribute__((visibility("default")))
#endif
#ifdef LIBASSERT_STATIC_DEFINE
#define LIBASSERT_EXPORT
#define LIBASSERT_NO_EXPORT
#else
#ifndef LIBASSERT_EXPORT
#ifdef libassert_lib_EXPORTS
/* We are building this library */
#define LIBASSERT_EXPORT LIBASSERT_EXPORT_ATTR
#else
/* We are using this library */
#define LIBASSERT_EXPORT LIBASSERT_IMPORT_ATTR
#endif
#endif
#endif
#if LIBASSERT_IS_CLANG || LIBASSERT_IS_GCC
#define LIBASSERT_PFUNC __extension__ __PRETTY_FUNCTION__
#define LIBASSERT_ATTR_COLD [[gnu::cold]]
#define LIBASSERT_ATTR_NOINLINE [[gnu::noinline]]
#define LIBASSERT_UNREACHABLE_CALL __builtin_unreachable()
#else
#define LIBASSERT_PFUNC __FUNCSIG__
#define LIBASSERT_ATTR_COLD
#define LIBASSERT_ATTR_NOINLINE __declspec(noinline)
#define LIBASSERT_UNREACHABLE_CALL __assume(false)
#endif
#if LIBASSERT_IS_MSVC
#define LIBASSERT_STRONG_EXPECT(expr, value) (expr)
#elif defined(__clang__) && __clang_major__ >= 11 || __GNUC__ >= 9
#define LIBASSERT_STRONG_EXPECT(expr, value) __builtin_expect_with_probability((expr), (value), 1)
#else
#define LIBASSERT_STRONG_EXPECT(expr, value) __builtin_expect((expr), (value))
#endif
// deal with gcc shenanigans
// at one point their std::string's move assignment was not noexcept even in c++17
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
#if defined(_GLIBCXX_USE_CXX11_ABI)
// NOLINTNEXTLINE(misc-include-cleaner)
#define LIBASSERT_GCC_ISNT_STUPID _GLIBCXX_USE_CXX11_ABI
#else
// assume others target new abi by default - homework
#define LIBASSERT_GCC_ISNT_STUPID 1
#endif
#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL
#define LIBASSERT_NON_CONFORMANT_MSVC_PREPROCESSOR true
#else
#define LIBASSERT_NON_CONFORMANT_MSVC_PREPROCESSOR false
#endif
#if (LIBASSERT_IS_GCC || LIBASSERT_STD_VER >= 20) && !LIBASSERT_NON_CONFORMANT_MSVC_PREPROCESSOR
// __VA_OPT__ needed for GCC, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44317
#define LIBASSERT_VA_ARGS(...) __VA_OPT__(,) __VA_ARGS__
#else
// clang properly eats the comma with ##__VA_ARGS__
#define LIBASSERT_VA_ARGS(...) , ##__VA_ARGS__
#endif
///
/// C++20 functionality wrappers.
///
// Check if we can use std::is_constant_evaluated.
#ifdef __has_include
#if __has_include(<version>)
#include <version>
#ifdef __cpp_lib_is_constant_evaluated
#include <type_traits>
#define LIBASSERT_HAS_IS_CONSTANT_EVALUATED
#endif
#endif
#endif
// Check if we have the builtin __builtin_is_constant_evaluated.
#ifdef __has_builtin
#if __has_builtin(__builtin_is_constant_evaluated)
#define LIBASSERT_HAS_BUILTIN_IS_CONSTANT_EVALUATED
#endif
#endif
// GCC 9.1+ and later has __builtin_is_constant_evaluated
#if (__GNUC__ >= 9) && !defined(LIBASSERT_HAS_BUILTIN_IS_CONSTANT_EVALUATED)
#define LIBASSERT_HAS_BUILTIN_IS_CONSTANT_EVALUATED
#endif
// Visual Studio 2019 (19.25) and later supports __builtin_is_constant_evaluated
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 192528326)
#define LIBASSERT_HAS_BUILTIN_IS_CONSTANT_EVALUATED
#endif
namespace libassert::detail {
// Note: Works with >=C++20 and with C++17 for GCC 9.1+, Clang 9+, and MSVC 19.25+.
constexpr bool is_constant_evaluated() noexcept {
#if defined(LIBASSERT_HAS_IS_CONSTANT_EVALUATED)
return std::is_constant_evaluated();
#elif defined(LIBASSERT_HAS_BUILTIN_IS_CONSTANT_EVALUATED)
return __builtin_is_constant_evaluated();
#else
return false;
#endif
}
}
#if LIBASSERT_IS_CLANG || LIBASSERT_IS_GCC
#if LIBASSERT_IS_GCC
#define LIBASSERT_WARNING_PRAGMA_PUSH_GCC _Pragma("GCC diagnostic push")
#define LIBASSERT_WARNING_PRAGMA_POP_GCC _Pragma("GCC diagnostic pop")
#define LIBASSERT_WARNING_PRAGMA_PUSH_CLANG
#define LIBASSERT_WARNING_PRAGMA_POP_CLANG
#else
#define LIBASSERT_WARNING_PRAGMA_PUSH_GCC
#define LIBASSERT_WARNING_PRAGMA_POP_GCC
#define LIBASSERT_WARNING_PRAGMA_PUSH_CLANG _Pragma("GCC diagnostic push")
#define LIBASSERT_WARNING_PRAGMA_POP_CLANG _Pragma("GCC diagnostic pop")
#endif
#else
#define LIBASSERT_WARNING_PRAGMA_PUSH_CLANG
#define LIBASSERT_WARNING_PRAGMA_POP_CLANG
#define LIBASSERT_WARNING_PRAGMA_PUSH_GCC
#define LIBASSERT_WARNING_PRAGMA_POP_GCC
#endif
#if LIBASSERT_IS_CLANG || LIBASSERT_IS_ICX
// clang and icx support this as far back as this library could care
#define LIBASSERT_BREAKPOINT() __builtin_debugtrap()
#elif LIBASSERT_IS_MSVC || LIBASSERT_IS_ICC
// msvc and icc support this as far back as this library could care
#define LIBASSERT_BREAKPOINT() __debugbreak()
#elif LIBASSERT_IS_GCC
#if LIBASSERT_GCC_VERSION >= 1200
#define LIBASSERT_IGNORE_CPP20_EXTENSION_WARNING _Pragma("GCC diagnostic ignored \"-Wc++20-extensions\"")
#else
#define LIBASSERT_IGNORE_CPP20_EXTENSION_WARNING
#endif
#define LIBASSERT_ASM_BREAKPOINT(instruction) \
do { \
LIBASSERT_WARNING_PRAGMA_PUSH_GCC \
LIBASSERT_IGNORE_CPP20_EXTENSION_WARNING \
__asm__ __volatile__(instruction) \
; \
LIBASSERT_WARNING_PRAGMA_POP_GCC \
} while(0)
// precedence for these come from llvm's __builtin_debugtrap() implementation
// arm: https://github.com/llvm/llvm-project/blob/e9954ec087d640809082f46d1c7e5ac1767b798d/llvm/lib/Target/ARM/ARMInstrInfo.td#L2393-L2394
// def : Pat<(debugtrap), (BKPT 0)>, Requires<[IsARM, HasV5T]>;
// def : Pat<(debugtrap), (UDF 254)>, Requires<[IsARM, NoV5T]>;
// thumb: https://github.com/llvm/llvm-project/blob/e9954ec087d640809082f46d1c7e5ac1767b798d/llvm/lib/Target/ARM/ARMInstrThumb.td#L1444-L1445
// def : Pat<(debugtrap), (tBKPT 0)>, Requires<[IsThumb, HasV5T]>;
// def : Pat<(debugtrap), (tUDF 254)>, Requires<[IsThumb, NoV5T]>;
// aarch64: https://github.com/llvm/llvm-project/blob/e9954ec087d640809082f46d1c7e5ac1767b798d/llvm/lib/Target/AArch64/AArch64FastISel.cpp#L3615-L3618
// case Intrinsic::debugtrap:
// BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(AArch64::BRK))
// .addImm(0xF000);
// return true;
// x86: https://github.com/llvm/llvm-project/blob/e9954ec087d640809082f46d1c7e5ac1767b798d/llvm/lib/Target/X86/X86InstrSystem.td#L81-L84
// def : Pat<(debugtrap),
// (INT3)>, Requires<[NotPS]>;
#if defined(__i386__) || defined(__x86_64__)
#define LIBASSERT_BREAKPOINT() LIBASSERT_ASM_BREAKPOINT("int3")
#elif defined(__arm__) || defined(__thumb__)
#if __ARM_ARCH >= 5
#define LIBASSERT_BREAKPOINT() LIBASSERT_ASM_BREAKPOINT("bkpt #0")
#else
#define LIBASSERT_BREAKPOINT() LIBASSERT_ASM_BREAKPOINT("udf #0xfe")
#endif
#elif defined(__aarch64__) || defined(_M_ARM64)
#define LIBASSERT_BREAKPOINT() LIBASSERT_ASM_BREAKPOINT("brk #0xf000")
#else
// some architecture we aren't prepared for
#define LIBASSERT_BREAKPOINT()
#endif
#else
// some compiler we aren't prepared for
#define LIBASSERT_BREAKPOINT()
#endif
#endif