diff --git a/openmp/libomptarget/DeviceRTL/include/Debug.h b/openmp/libomptarget/DeviceRTL/include/Debug.h --- a/openmp/libomptarget/DeviceRTL/include/Debug.h +++ b/openmp/libomptarget/DeviceRTL/include/Debug.h @@ -12,16 +12,30 @@ #ifndef OMPTARGET_DEVICERTL_DEBUG_H #define OMPTARGET_DEVICERTL_DEBUG_H +#include "Configuration.h" +#include "Utils.h" + /// Assertion /// /// { extern "C" { -void __assert_assume(bool cond, const char *exp, const char *file, int line); +void __assert_assume(bool cond, bool enabled, bool print, const char *exp, + const char *file, int line); void __assert_fail(const char *assertion, const char *file, unsigned line, const char *function); } -#define ASSERT(e) __assert_assume(e, #e, __FILE__, __LINE__) +/// Helper expansion for ASSERT. \p Cond is the expression in the assertion, +/// \p Enabled determines if assertions are enabled at all, \p ID is a unique +/// identifier for the assertion so we can ensure it is only reported once. +#define ASSERT_IMPL(Cond, Enabled) \ + __assert_assume(Cond, Enabled, Enabled &&utils::SingletonFlag::testAndSet(), \ + #Cond, __FILE__, __LINE__) + +/// Assert \p Cond holds. If assertions are enabled it will check it, otherwise +/// simply assume it holds. +#define ASSERT(Cond) \ + ASSERT_IMPL(Cond, config::isDebugMode(config::DebugKind::Assertion)) ///} diff --git a/openmp/libomptarget/DeviceRTL/include/Synchronization.h b/openmp/libomptarget/DeviceRTL/include/Synchronization.h --- a/openmp/libomptarget/DeviceRTL/include/Synchronization.h +++ b/openmp/libomptarget/DeviceRTL/include/Synchronization.h @@ -74,6 +74,10 @@ /// Atomically add \p V to \p *Addr with \p Ordering semantics. uint64_t add(uint64_t *Addr, uint64_t V, int Ordering); +/// Atomically write \p V to \p *Addr with \p Ordering semantics and return the +/// old value of \p *Addr. +uint32_t exchange(uint32_t *Addr, uint32_t V, int Ordering); + } // namespace atomic } // namespace _OMP diff --git a/openmp/libomptarget/DeviceRTL/include/Utils.h b/openmp/libomptarget/DeviceRTL/include/Utils.h --- a/openmp/libomptarget/DeviceRTL/include/Utils.h +++ b/openmp/libomptarget/DeviceRTL/include/Utils.h @@ -12,6 +12,7 @@ #ifndef OMPTARGET_DEVICERTL_UTILS_H #define OMPTARGET_DEVICERTL_UTILS_H +#include "Synchronization.h" #include "Types.h" namespace _OMP { @@ -72,6 +73,24 @@ return V - V % Align; } +/// Helper class to perform an action only once. +/// +/// Using this is probably costly even if it is not executed. It should be +/// guarded such that release mode execution will not be impacted. +template struct SingletonFlagImpl { + + /// Each SingletonFlag instantiation with the same ID has an internal flag. + /// This function will return true if the flag was not set before, otherwise + /// it will return false. In either case the flag is set afterwards. + static bool testAndSet() { + static uint32_t DoOnceFlag = 0; + return 1 != atomic::exchange(&DoOnceFlag, 1, __ATOMIC_ACQ_REL); + } +}; + +/// Helper to hide the __COUNTER__ use away. +#define SingletonFlag SingletonFlagImpl<__COUNTER__> + #define OMP_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) #define OMP_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) diff --git a/openmp/libomptarget/DeviceRTL/src/Debug.cpp b/openmp/libomptarget/DeviceRTL/src/Debug.cpp --- a/openmp/libomptarget/DeviceRTL/src/Debug.cpp +++ b/openmp/libomptarget/DeviceRTL/src/Debug.cpp @@ -20,9 +20,12 @@ #pragma omp declare target extern "C" { -void __assert_assume(bool cond, const char *exp, const char *file, int line) { - if (!cond && config::isDebugMode(config::DebugKind::Assertion)) { - PRINTF("ASSERTION failed: %s at %s, line %d\n", exp, file, line); +void __assert_assume(bool cond, bool enabled, bool print, const char *exp, + const char *file, int line) { + // TODO: Consider printing the thread coordinates as well. + if (enabled && !cond) { + if (print) + PRINTF("ASSERTION failed: %s at %s, line %d\n", exp, file, line); __builtin_trap(); } diff --git a/openmp/libomptarget/DeviceRTL/src/Synchronization.cpp b/openmp/libomptarget/DeviceRTL/src/Synchronization.cpp --- a/openmp/libomptarget/DeviceRTL/src/Synchronization.cpp +++ b/openmp/libomptarget/DeviceRTL/src/Synchronization.cpp @@ -259,6 +259,10 @@ return impl::atomicAdd(Addr, V, Ordering); } +uint32_t atomic::exchange(uint32_t *Addr, uint32_t V, int Ordering) { + return impl::atomicExchange(Addr, V, Ordering); +} + extern "C" { void __kmpc_ordered(IdentTy *Loc, int32_t TId) {}