diff --git a/Eigen/Core b/Eigen/Core index cb5ef55e5..af7189162 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -82,9 +82,6 @@ #include #include #include -#ifndef __SYCL_DEVICE_ONLY__ -#include -#endif #include #ifndef EIGEN_NO_IO #include @@ -160,6 +157,7 @@ using std::ptrdiff_t; #include "src/Core/util/Constants.h" #include "src/Core/util/Meta.h" +#include "src/Core/util/Assert.h" #include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" diff --git a/Eigen/src/Core/util/Assert.h b/Eigen/src/Core/util/Assert.h new file mode 100644 index 000000000..f8ba63297 --- /dev/null +++ b/Eigen/src/Core/util/Assert.h @@ -0,0 +1,166 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2022, The Eigen authors. +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_CORE_UTIL_ASSERT_H +#define EIGEN_CORE_UTIL_ASSERT_H + +// Eigen custom assert function. +// +// The combination of Eigen's relative includes and cassert's `assert` function +// (or any usage of the __FILE__ macro) can lead to ODR issues: +// a header included using different relative paths in two different TUs will +// have two different token-for-token definitions, since __FILE__ is expanded +// as an in-line string with different values. Normally this would be +// harmless - the linker would just choose one definition. However, it breaks +// with C++20 modules when functions in different modules have different +// definitions. +// +// To get around this, we need to use __builtin_FILE() when available, which is +// considered a single token, and thus satisfies the ODR. + +// Only define eigen_plain_assert if we are debugging, and either +// - we are not compiling for GPU, or +// - gpu debugging is enabled. +#if !defined(EIGEN_NO_DEBUG) && (!defined(EIGEN_GPU_COMPILE_PHASE) || !defined(EIGEN_NO_DEBUG_GPU)) + +#include + +#ifndef EIGEN_USE_CUSTOM_PLAIN_ASSERT +// Disable new custom asserts by default for now. +#define EIGEN_USE_CUSTOM_PLAIN_ASSERT 0 +#endif + +#if EIGEN_USE_CUSTOM_PLAIN_ASSERT + +#ifndef EIGEN_HAS_BUILTIN_FILE +// Clang can check if __builtin_FILE() is supported. +// GCC > 5, MSVC 2019 14.26 (1926) all have __builtin_FILE(). +// +// For NVCC, it's more complicated. Through trial-and-error: +// - nvcc+gcc supports __builtin_FILE() on host, and on device after CUDA 11. +// - nvcc+msvc supports __builtin_FILE() only after CUDA 11. +#if (EIGEN_HAS_BUILTIN(__builtin_FILE) && (EIGEN_COMP_CLANG || !defined(EIGEN_CUDA_ARCH))) || \ + (EIGEN_GNUC_STRICT_AT_LEAST(5, 0, 0) && (EIGEN_COMP_NVCC >= 110000 || !defined(EIGEN_CUDA_ARCH))) || \ + (EIGEN_COMP_MSVC >= 1926 && (!EIGEN_COMP_NVCC || EIGEN_COMP_NVCC >= 110000)) +#define EIGEN_HAS_BUILTIN_FILE 1 +#else +#define EIGEN_HAS_BUILTIN_FILE 0 +#endif +#endif // EIGEN_HAS_BUILTIN_FILE + +#if EIGEN_HAS_BUILTIN_FILE +# define EIGEN_BUILTIN_FILE __builtin_FILE() +# define EIGEN_BUILTIN_LINE __builtin_LINE() +#else +// Default (potentially unsafe) values. +# define EIGEN_BUILTIN_FILE __FILE__ +# define EIGEN_BUILTIN_LINE __LINE__ +#endif + +// Use __PRETTY_FUNCTION__ when available, since it is more descriptive, as +// __builtin_FUNCTION() only returns the undecorated function name. +// This should still be okay ODR-wise since it is a compiler-specific fixed +// value. Mixing compilers will likely lead to ODR violations anyways. +#if EIGEN_COMP_MSVC +# define EIGEN_BUILTIN_FUNCTION __FUNCSIG__ +#elif EIGEN_COMP_GNUC +# define EIGEN_BUILTIN_FUNCTION __PRETTY_FUNCTION__ +#else +# define EIGEN_BUILTIN_FUNCTION __func__ +#endif + +namespace Eigen { +namespace internal { + +// Generic default assert handler. +template +struct assert_handler_impl { + EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE + static inline void run(const char* expression, const char* file, unsigned line, const char* function) { +#ifdef EIGEN_GPU_COMPILE_PHASE + // GPU device code doesn't allow stderr or abort, so use printf and raise an + // illegal instruction exception to trigger a kernel failure. +#ifndef EIGEN_NO_IO + printf("Assertion failed at %s:%u in %s: %s\n", + file == nullptr ? "" : file, + line, + function == nullptr ? "" : function, + expression); +#endif + __trap(); + +#else // EIGEN_GPU_COMPILE_PHASE + + // Print to stderr and abort, as specified in . +#ifndef EIGEN_NO_IO + fprintf(stderr, "Assertion failed at %s:%u in %s: %s\n", + file == nullptr ? "" : file, + line, + function == nullptr ? "" : function, + expression); +#endif + std::abort(); + +#endif // EIGEN_GPU_COMPILE_PHASE + } +}; + +// Use POSIX __assert_fail handler when available. +// +// This allows us to integrate with systems that have custom handlers. +// +// NOTE: this handler is not always available on all POSIX systems (otherwise +// we could simply test for __unix__ or similar). The handler function name +// seems to depend on the specific toolchain implementation, and differs between +// compilers, platforms, OSes, etc. Hence, we detect support via SFINAE. +template +struct assert_handler_impl< + void_t()... // Empty substitution required for SFINAE. + ))>, EmptyArgs... > { + EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE + static inline void run(const char* expression, const char* file, unsigned line, const char* function) { + // GCC requires this call to be dependent on the template parameters. + __assert_fail(expression, file, line, function, std::declval()...); + } +}; + +EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE +inline void __assert_handler(const char* expression, const char* file, unsigned line, const char* function) { + assert_handler_impl<>::run(expression, file, line, function); +} + +} // namespace internal +} // namespace Eigen + +#define eigen_plain_assert(expression) \ + (EIGEN_PREDICT_FALSE(!(expression)) ? \ + Eigen::internal::__assert_handler(#expression, \ + EIGEN_BUILTIN_FILE, \ + EIGEN_BUILTIN_LINE, \ + EIGEN_BUILTIN_FUNCTION) : (void)0) + +#else // EIGEN_USE_CUSTOM_PLAIN_ASSERT + +// Use regular assert. +#define eigen_plain_assert(condition) assert(condition) + +#endif // EIGEN_USE_CUSTOM_PLAIN_ASSERT + +#else // EIGEN_NO_DEBUG + +#define eigen_plain_assert(condition) ((void)0) + +#endif // EIGEN_NO_DEBUG + +#endif // EIGEN_CORE_UTIL_ASSERT_H diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 026d1740b..819fa12a3 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -848,8 +848,8 @@ // GPU stuff -// Disable some features when compiling with GPU compilers (NVCC/clang-cuda/SYCL/HIPCC) -#if defined(EIGEN_CUDACC) || defined(SYCL_DEVICE_ONLY) || defined(EIGEN_HIPCC) +// Disable some features when compiling with GPU compilers (SYCL/HIPCC) +#if defined(SYCL_DEVICE_ONLY) || defined(EIGEN_HIP_DEVICE_COMPILE) // Do not try asserts on device code #ifndef EIGEN_NO_DEBUG #define EIGEN_NO_DEBUG @@ -858,7 +858,10 @@ #ifdef EIGEN_INTERNAL_DEBUGGING #undef EIGEN_INTERNAL_DEBUGGING #endif +#endif +// No exceptions on device. +#if defined(SYCL_DEVICE_ONLY) || defined(EIGEN_GPU_COMPILE_PHASE) #ifdef EIGEN_EXCEPTIONS #undef EIGEN_EXCEPTIONS #endif @@ -890,17 +893,6 @@ # endif #endif -// eigen_plain_assert is where we implement the workaround for the assert() bug in GCC <= 4.3, see bug 89 -#ifdef EIGEN_NO_DEBUG - #ifdef SYCL_DEVICE_ONLY // used to silence the warning on SYCL device - #define eigen_plain_assert(x) EIGEN_UNUSED_VARIABLE(x) - #else - #define eigen_plain_assert(x) - #endif -#else - #define eigen_plain_assert(x) assert(x) -#endif - // eigen_assert can be overridden #ifndef eigen_assert #define eigen_assert(x) eigen_plain_assert(x) @@ -912,7 +904,7 @@ #define eigen_internal_assert(x) ((void)0) #endif -#ifdef EIGEN_NO_DEBUG +#if defined(EIGEN_NO_DEBUG) || (defined(EIGEN_GPU_COMPILE_PHASE) && defined(EIGEN_NO_DEBUG_GPU)) #define EIGEN_ONLY_USED_FOR_DEBUG(x) EIGEN_UNUSED_VARIABLE(x) #else #define EIGEN_ONLY_USED_FOR_DEBUG(x) diff --git a/Eigen/src/Core/util/Meta.h b/Eigen/src/Core/util/Meta.h index 9c02514e4..1a5d515ed 100644 --- a/Eigen/src/Core/util/Meta.h +++ b/Eigen/src/Core/util/Meta.h @@ -153,6 +153,21 @@ template struct is_same { enum { value = 1 }; }; template< class T > struct is_void : is_same> {}; +/** \internal + * Implementation of std::void_t for SFINAE. + * + * Pre C++17: + * Custom implementation. + * + * Post C++17: Uses std::void_t + */ +#if EIGEN_COMP_CXXVER >= 17 +using std::void_t; +#else +template +using void_t = void; +#endif + template<> struct is_arithmetic { enum { value = true }; }; template<> struct is_arithmetic { enum { value = true }; }; using std::is_integral;