mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01: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 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
|
struct info
|
||||||
{
|
{
|
||||||
const void* data;
|
const void* data;
|
||||||
@ -121,29 +151,13 @@ namespace atomic_wait
|
|||||||
__m128i old;
|
__m128i old;
|
||||||
__m128i mask;
|
__m128i mask;
|
||||||
|
|
||||||
template <typename T>
|
template <typename X, typename T = decltype(std::declval<X>().observe())>
|
||||||
static constexpr __m128i get_value(T value = T{})
|
constexpr void set_value(X& a, T value = T{})
|
||||||
{
|
{
|
||||||
static_assert((sizeof(T) & (sizeof(T) - 1)) == 0);
|
old = get_value(a, value);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename X, typename T = decltype(std::declval<X>().observe())>
|
||||||
constexpr void set_value(T value = T{})
|
|
||||||
{
|
|
||||||
old = get_value<T>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr void set_mask(T value)
|
constexpr void set_mask(T value)
|
||||||
{
|
{
|
||||||
static_assert((sizeof(T) & (sizeof(T) - 1)) == 0);
|
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()
|
constexpr void set_mask()
|
||||||
{
|
{
|
||||||
mask = get_mask<T>();
|
mask = default_mask<X>;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -194,9 +195,9 @@ namespace atomic_wait
|
|||||||
|
|
||||||
constexpr list& operator=(const list&) noexcept = default;
|
constexpr list& operator=(const list&) noexcept = default;
|
||||||
|
|
||||||
template <typename... U, std::size_t... Align>
|
template <typename... U, typename = std::void_t<decltype(std::declval<U>().template wait<op::eq>(any_value))...>>
|
||||||
constexpr list(atomic_t<U, Align>&... vars)
|
constexpr list(U&... vars)
|
||||||
: m_info{{&vars.raw(), sizeof(U), info::get_value<U>(), info::get_mask<U>()}...}
|
: m_info{{&vars, sizeof(vars.observe()), get_value(vars), default_mask<U>}...}
|
||||||
{
|
{
|
||||||
static_assert(sizeof...(U) == Max, "Inconsistent amount of atomics.");
|
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.");
|
static_assert(sizeof...(U) == Max, "Inconsistent amount of values.");
|
||||||
|
|
||||||
auto* ptr = m_info;
|
auto* ptr = m_info;
|
||||||
((ptr++)->template set_value<T>(values), ...);
|
((ptr->template set_value<T>(*static_cast<T*>(ptr->data), values), ptr++), ...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,25 +222,25 @@ namespace atomic_wait
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint Index, op Flags = op::eq, typename T2, std::size_t Align, typename U>
|
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(atomic_t<T2, Align>& var, U value)
|
constexpr void set(T2& var, U value)
|
||||||
{
|
{
|
||||||
static_assert(Index < Max);
|
static_assert(Index < Max);
|
||||||
|
|
||||||
m_info[Index].data = &var.raw();
|
m_info[Index].data = &var;
|
||||||
m_info[Index].size = sizeof(T2) | (static_cast<u8>(Flags) << 8);
|
m_info[Index].size = sizeof(var.observe()) | (static_cast<u8>(Flags) << 8);
|
||||||
m_info[Index].template set_value<T2>(value);
|
m_info[Index].template set_value<T2>(var, value);
|
||||||
m_info[Index].template set_mask<T2>();
|
m_info[Index].template set_mask<T2>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <uint Index, op Flags = op::eq, typename T2, std::size_t Align, typename U, typename V>
|
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(atomic_t<T2, Align>& var, U value, V mask)
|
constexpr void set(T2& var, U value, V mask)
|
||||||
{
|
{
|
||||||
static_assert(Index < Max);
|
static_assert(Index < Max);
|
||||||
|
|
||||||
m_info[Index].data = &var.raw();
|
m_info[Index].data = &var;
|
||||||
m_info[Index].size = sizeof(T2) | (static_cast<u8>(Flags) << 8);
|
m_info[Index].size = sizeof(var.observe()) | (static_cast<u8>(Flags) << 8);
|
||||||
m_info[Index].template set_value<T2>(value);
|
m_info[Index].template set_value<T2>(var, value);
|
||||||
m_info[Index].template set_mask<T2>(mask);
|
m_info[Index].template set_mask<T2>(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,8 +254,8 @@ namespace atomic_wait
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... T, std::size_t... Align>
|
template <typename... T, typename = std::void_t<decltype(std::declval<T>().template wait<op::eq>(any_value))...>>
|
||||||
list(atomic_t<T, Align>&... vars) -> list<sizeof...(T), T...>;
|
list(T&... vars) -> list<sizeof...(T), T...>;
|
||||||
|
|
||||||
// RDTSC with adjustment for being unique
|
// RDTSC with adjustment for being unique
|
||||||
u64 get_unique_tsc();
|
u64 get_unique_tsc();
|
||||||
@ -1719,3 +1720,9 @@ public:
|
|||||||
base::notify_all(1);
|
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