atomic.cpp: fix memory ordering loads and release stores

This commit is contained in:
Eladash 2020-10-28 16:39:35 +02:00 committed by Ivan
parent 6f5bbf550a
commit e791678dfc

View file

@ -248,6 +248,7 @@ struct atomic_storage<T, 1> : atomic_storage<T, 0>
static inline T load(const T& dest) static inline T load(const T& dest)
{ {
std::atomic_thread_fence(std::memory_order_acquire);
const char value = *reinterpret_cast<const volatile char*>(&dest); const char value = *reinterpret_cast<const volatile char*>(&dest);
std::atomic_thread_fence(std::memory_order_acquire); std::atomic_thread_fence(std::memory_order_acquire);
return std::bit_cast<T>(value); return std::bit_cast<T>(value);
@ -257,6 +258,7 @@ struct atomic_storage<T, 1> : atomic_storage<T, 0>
{ {
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
*reinterpret_cast<volatile char*>(&dest) = std::bit_cast<char>(value); *reinterpret_cast<volatile char*>(&dest) = std::bit_cast<char>(value);
std::atomic_thread_fence(std::memory_order_release);
} }
static inline T exchange(T& dest, T value) static inline T exchange(T& dest, T value)
@ -310,6 +312,7 @@ struct atomic_storage<T, 2> : atomic_storage<T, 0>
static inline T load(const T& dest) static inline T load(const T& dest)
{ {
std::atomic_thread_fence(std::memory_order_acquire);
const short value = *reinterpret_cast<const volatile short*>(&dest); const short value = *reinterpret_cast<const volatile short*>(&dest);
std::atomic_thread_fence(std::memory_order_acquire); std::atomic_thread_fence(std::memory_order_acquire);
return std::bit_cast<T>(value); return std::bit_cast<T>(value);
@ -319,6 +322,7 @@ struct atomic_storage<T, 2> : atomic_storage<T, 0>
{ {
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
*reinterpret_cast<volatile short*>(&dest) = std::bit_cast<short>(value); *reinterpret_cast<volatile short*>(&dest) = std::bit_cast<short>(value);
std::atomic_thread_fence(std::memory_order_release);
} }
static inline T exchange(T& dest, T value) static inline T exchange(T& dest, T value)
@ -416,6 +420,7 @@ struct atomic_storage<T, 4> : atomic_storage<T, 0>
static inline T load(const T& dest) static inline T load(const T& dest)
{ {
std::atomic_thread_fence(std::memory_order_acquire);
const long value = *reinterpret_cast<const volatile long*>(&dest); const long value = *reinterpret_cast<const volatile long*>(&dest);
std::atomic_thread_fence(std::memory_order_acquire); std::atomic_thread_fence(std::memory_order_acquire);
return std::bit_cast<T>(value); return std::bit_cast<T>(value);
@ -425,6 +430,7 @@ struct atomic_storage<T, 4> : atomic_storage<T, 0>
{ {
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
*reinterpret_cast<volatile long*>(&dest) = std::bit_cast<long>(value); *reinterpret_cast<volatile long*>(&dest) = std::bit_cast<long>(value);
std::atomic_thread_fence(std::memory_order_release);
} }
static inline T exchange(T& dest, T value) static inline T exchange(T& dest, T value)
@ -535,6 +541,7 @@ struct atomic_storage<T, 8> : atomic_storage<T, 0>
static inline T load(const T& dest) static inline T load(const T& dest)
{ {
std::atomic_thread_fence(std::memory_order_acquire);
const llong value = *reinterpret_cast<const volatile llong*>(&dest); const llong value = *reinterpret_cast<const volatile llong*>(&dest);
std::atomic_thread_fence(std::memory_order_acquire); std::atomic_thread_fence(std::memory_order_acquire);
return std::bit_cast<T>(value); return std::bit_cast<T>(value);
@ -544,6 +551,7 @@ struct atomic_storage<T, 8> : atomic_storage<T, 0>
{ {
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
*reinterpret_cast<volatile llong*>(&dest) = std::bit_cast<llong>(value); *reinterpret_cast<volatile llong*>(&dest) = std::bit_cast<llong>(value);
std::atomic_thread_fence(std::memory_order_release);
} }
static inline T exchange(T& dest, T value) static inline T exchange(T& dest, T value)
@ -641,6 +649,7 @@ struct atomic_storage<T, 16> : atomic_storage<T, 0>
#ifdef _MSC_VER #ifdef _MSC_VER
static inline T load(const T& dest) static inline T load(const T& dest)
{ {
std::atomic_thread_fence(std::memory_order_acquire);
__m128i val = _mm_load_si128(reinterpret_cast<const __m128i*>(&dest)); __m128i val = _mm_load_si128(reinterpret_cast<const __m128i*>(&dest));
std::atomic_thread_fence(std::memory_order_acquire); std::atomic_thread_fence(std::memory_order_acquire);
return std::bit_cast<T>(val); return std::bit_cast<T>(val);
@ -673,10 +682,12 @@ struct atomic_storage<T, 16> : atomic_storage<T, 0>
{ {
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
_mm_store_si128(reinterpret_cast<__m128i*>(&dest), std::bit_cast<__m128i>(value)); _mm_store_si128(reinterpret_cast<__m128i*>(&dest), std::bit_cast<__m128i>(value));
std::atomic_thread_fence(std::memory_order_release);
} }
#else #else
static inline T load(const T& dest) static inline T load(const T& dest)
{ {
__atomic_thread_fence(__ATOMIC_ACQUIRE);
__m128i val = _mm_load_si128(reinterpret_cast<const __m128i*>(&dest)); __m128i val = _mm_load_si128(reinterpret_cast<const __m128i*>(&dest));
__atomic_thread_fence(__ATOMIC_ACQUIRE); __atomic_thread_fence(__ATOMIC_ACQUIRE);
return std::bit_cast<T>(val); return std::bit_cast<T>(val);
@ -741,6 +752,7 @@ struct atomic_storage<T, 16> : atomic_storage<T, 0>
{ {
__atomic_thread_fence(__ATOMIC_RELEASE); __atomic_thread_fence(__ATOMIC_RELEASE);
_mm_store_si128(reinterpret_cast<__m128i*>(&dest), std::bit_cast<__m128i>(value)); _mm_store_si128(reinterpret_cast<__m128i*>(&dest), std::bit_cast<__m128i>(value));
__atomic_thread_fence(__ATOMIC_RELEASE);
} }
#endif #endif