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 @@ -13,6 +13,7 @@ #define OMPTARGET_DEVICERTL_DEBUG_H #include "Configuration.h" +#include "Utils.h" /// Assertion /// @@ -25,9 +26,10 @@ #define ASSERT(expr) \ { \ - if (config::isDebugMode(config::DebugKind::Assertion) && !(expr)) \ + if (config::isDebugMode(config::DebugKind::Assertion) && !(expr) && \ + utils::SingletonFlag::testAndSet()) \ __assert_fail(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - else \ + else if (!config::isDebugMode(config::DebugKind::Assertion)) \ __assert_assume(expr); \ } 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,26 @@ return V - V % Align; } +namespace { +/// 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); + } +}; +} // namespace + +/// 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/Synchronization.cpp b/openmp/libomptarget/DeviceRTL/src/Synchronization.cpp --- a/openmp/libomptarget/DeviceRTL/src/Synchronization.cpp +++ b/openmp/libomptarget/DeviceRTL/src/Synchronization.cpp @@ -320,6 +320,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) { FunctionTracingRAII(); }