mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 08:11:51 +00:00
atomic.hpp: use SFINAE for waitable atomic detection
Add default_mask<> variable. Refactor get_value<>().
This commit is contained in:
parent
bfe1a8673a
commit
4a883ba6ea
@ -114,6 +114,36 @@ namespace atomic_wait
|
||||
|
||||
constexpr op op_ne = op::eq | op_flag::inverse;
|
||||
|
||||
constexpr struct any_value_t
|
||||
{
|
||||
template <typename T>
|
||||
operator T() const noexcept
|
||||
{
|
||||
return T();
|
||||
}
|
||||
} any_value;
|
||||
|
||||
template <typename X, typename T = decltype(std::declval<X>().observe())>
|
||||
inline __m128i default_mask = sizeof(T) <= 8
|
||||
? _mm_cvtsi64_si128(UINT64_MAX >> ((64 - sizeof(T) * 8) & 63))
|
||||
: _mm_set1_epi64x(-1);
|
||||
|
||||
template <typename X, typename T = decltype(std::declval<X>().observe())>
|
||||
constexpr __m128i get_value(X&, T value = T{}, ...)
|
||||
{
|
||||
static_assert((sizeof(T) & (sizeof(T) - 1)) == 0);
|
||||
static_assert(sizeof(T) <= 16);
|
||||
|
||||
if constexpr (sizeof(T) <= 8)
|
||||
{
|
||||
return _mm_cvtsi64_si128(std::bit_cast<get_uint_t<sizeof(T)>, T>(value));
|
||||
}
|
||||
else if constexpr (sizeof(T) == 16)
|
||||
{
|
||||
return std::bit_cast<__m128i>(value);
|
||||
}
|
||||
}
|
||||
|
||||
struct info
|
||||
{
|
||||
const void* data;
|
||||
@ -121,29 +151,13 @@ namespace atomic_wait
|
||||
__m128i old;
|
||||
__m128i mask;
|
||||
|
||||
template <typename T>
|
||||
static constexpr __m128i get_value(T value = T{})
|
||||
template <typename X, typename T = decltype(std::declval<X>().observe())>
|
||||
constexpr void set_value(X& a, T value = T{})
|
||||
{
|
||||
static_assert((sizeof(T) & (sizeof(T) - 1)) == 0);
|
||||
static_assert(sizeof(T) <= 16);
|
||||
|
||||
if constexpr (sizeof(T) <= 8)
|
||||
{
|
||||
return _mm_cvtsi64_si128(std::bit_cast<get_uint_t<sizeof(T)>, T>(value));
|
||||
}
|
||||
else if constexpr (sizeof(T) == 16)
|
||||
{
|
||||
return std::bit_cast<__m128i>(value);
|
||||
}
|
||||
old = get_value(a, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr void set_value(T value = T{})
|
||||
{
|
||||
old = get_value<T>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename X, typename T = decltype(std::declval<X>().observe())>
|
||||
constexpr void set_mask(T value)
|
||||
{
|
||||
static_assert((sizeof(T) & (sizeof(T) - 1)) == 0);
|
||||
@ -159,23 +173,10 @@ namespace atomic_wait
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename X, typename T = decltype(std::declval<X>().observe())>
|
||||
constexpr void set_mask()
|
||||
{
|
||||
mask = get_mask<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static constexpr __m128i get_mask()
|
||||
{
|
||||
if constexpr (sizeof(T) <= 8)
|
||||
{
|
||||
return _mm_cvtsi64_si128(UINT64_MAX >> ((64 - sizeof(T) * 8) & 63));
|
||||
}
|
||||
else
|
||||
{
|
||||
return _mm_set1_epi64x(-1);
|
||||
}
|
||||
mask = default_mask<X>;
|
||||
}
|
||||
};
|
||||
|
||||
@ -194,9 +195,9 @@ namespace atomic_wait
|
||||
|
||||
constexpr list& operator=(const list&) noexcept = default;
|
||||
|
||||
template <typename... U, std::size_t... Align>
|
||||
constexpr list(atomic_t<U, Align>&... vars)
|
||||
: m_info{{&vars.raw(), sizeof(U), info::get_value<U>(), info::get_mask<U>()}...}
|
||||
template <typename... U, typename = std::void_t<decltype(std::declval<U>().template wait<op::eq>(any_value))...>>
|
||||
constexpr list(U&... vars)
|
||||
: m_info{{&vars, sizeof(vars.observe()), get_value(vars), default_mask<U>}...}
|
||||
{
|
||||
static_assert(sizeof...(U) == Max, "Inconsistent amount of atomics.");
|
||||
}
|
||||
@ -207,7 +208,7 @@ namespace atomic_wait
|
||||
static_assert(sizeof...(U) == Max, "Inconsistent amount of values.");
|
||||
|
||||
auto* ptr = m_info;
|
||||
((ptr++)->template set_value<T>(values), ...);
|
||||
((ptr->template set_value<T>(*static_cast<T*>(ptr->data), values), ptr++), ...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -221,25 +222,25 @@ namespace atomic_wait
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <uint Index, op Flags = op::eq, typename T2, std::size_t Align, typename U>
|
||||
constexpr void set(atomic_t<T2, Align>& var, U value)
|
||||
template <uint Index, op Flags = op::eq, typename T2, typename U, typename = std::void_t<decltype(std::declval<T2>().template wait<op::eq>(any_value))>>
|
||||
constexpr void set(T2& var, U value)
|
||||
{
|
||||
static_assert(Index < Max);
|
||||
|
||||
m_info[Index].data = &var.raw();
|
||||
m_info[Index].size = sizeof(T2) | (static_cast<u8>(Flags) << 8);
|
||||
m_info[Index].template set_value<T2>(value);
|
||||
m_info[Index].data = &var;
|
||||
m_info[Index].size = sizeof(var.observe()) | (static_cast<u8>(Flags) << 8);
|
||||
m_info[Index].template set_value<T2>(var, value);
|
||||
m_info[Index].template set_mask<T2>();
|
||||
}
|
||||
|
||||
template <uint Index, op Flags = op::eq, typename T2, std::size_t Align, typename U, typename V>
|
||||
constexpr void set(atomic_t<T2, Align>& var, U value, V mask)
|
||||
template <uint Index, op Flags = op::eq, typename T2, typename U, typename V, typename = std::void_t<decltype(std::declval<T2>().template wait<op::eq>(any_value))>>
|
||||
constexpr void set(T2& var, U value, V mask)
|
||||
{
|
||||
static_assert(Index < Max);
|
||||
|
||||
m_info[Index].data = &var.raw();
|
||||
m_info[Index].size = sizeof(T2) | (static_cast<u8>(Flags) << 8);
|
||||
m_info[Index].template set_value<T2>(value);
|
||||
m_info[Index].data = &var;
|
||||
m_info[Index].size = sizeof(var.observe()) | (static_cast<u8>(Flags) << 8);
|
||||
m_info[Index].template set_value<T2>(var, value);
|
||||
m_info[Index].template set_mask<T2>(mask);
|
||||
}
|
||||
|
||||
@ -253,8 +254,8 @@ namespace atomic_wait
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... T, std::size_t... Align>
|
||||
list(atomic_t<T, Align>&... vars) -> list<sizeof...(T), T...>;
|
||||
template <typename... T, typename = std::void_t<decltype(std::declval<T>().template wait<op::eq>(any_value))...>>
|
||||
list(T&... vars) -> list<sizeof...(T), T...>;
|
||||
|
||||
// RDTSC with adjustment for being unique
|
||||
u64 get_unique_tsc();
|
||||
@ -1719,3 +1720,9 @@ public:
|
||||
base::notify_all(1);
|
||||
}
|
||||
};
|
||||
|
||||
namespace atomic_wait
|
||||
{
|
||||
template <std::size_t Align>
|
||||
inline __m128i default_mask<atomic_t<bool, Align>> = _mm_cvtsi32_si128(1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user