atomic_t: cleanup type requirements

Add C++17 requirements.
Remove alignment requirements (auto-align type).
What's missing is to detect padding and forbid it.
This commit is contained in:
Nekotekina 2020-12-04 18:03:50 +03:00
parent 8efc22bd45
commit d1e7837422
6 changed files with 38 additions and 20 deletions

View file

@ -539,6 +539,12 @@ struct alignas(16) s128
CHECK_SIZE_ALIGN(u128, 16, 16); CHECK_SIZE_ALIGN(u128, 16, 16);
CHECK_SIZE_ALIGN(s128, 16, 16); CHECK_SIZE_ALIGN(s128, 16, 16);
template <>
struct get_int_impl<16>
{
using utype = u128;
};
// Return magic value for any unsigned type // Return magic value for any unsigned type
constexpr inline struct umax_helper constexpr inline struct umax_helper
{ {

View file

@ -144,7 +144,7 @@ struct audio_port
u32 size; u32 size;
u64 timestamp; // copy of global timestamp u64 timestamp; // copy of global timestamp
struct alignas(8) level_set_t struct level_set_t
{ {
float value; float value;
float inc; float inc;

View file

@ -410,7 +410,7 @@ bool squeue_test_exit();
template<typename T, u32 sq_size = 256> template<typename T, u32 sq_size = 256>
class squeue_t class squeue_t
{ {
struct alignas(8) squeue_sync_var_t struct squeue_sync_var_t
{ {
struct struct
{ {

View file

@ -692,7 +692,7 @@ struct alignas(128) CellSpurs
u8 xCA; // 0xCA u8 xCA; // 0xCA
u8 xCB; // 0xCB u8 xCB; // 0xCB
struct alignas(4) SrvTraceSyncVar struct SrvTraceSyncVar
{ {
u8 sysSrvTraceInitialised; // 0xCC u8 sysSrvTraceInitialised; // 0xCC
u8 sysSrvNotifyUpdateTraceComplete; // 0xCD u8 sysSrvNotifyUpdateTraceComplete; // 0xCD
@ -881,7 +881,7 @@ CHECK_SIZE_ALIGN(CellSpursWorkloadAttribute, 512, 8);
struct alignas(128) CellSpursEventFlag struct alignas(128) CellSpursEventFlag
{ {
struct alignas(8) ControlSyncVar struct ControlSyncVar
{ {
be_t<u16> events; // 0x00 Event bits be_t<u16> events; // 0x00 Event bits
be_t<u16> spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks be_t<u16> spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks

View file

@ -36,7 +36,7 @@ enum CellSyncError1 : u32
struct CellSyncMutex struct CellSyncMutex
{ {
struct alignas(4) Counter struct Counter
{ {
be_t<u16> rel; be_t<u16> rel;
be_t<u16> acq; be_t<u16> acq;
@ -162,7 +162,7 @@ CHECK_SIZE_ALIGN(CellSyncRwm, 16, 16);
struct alignas(32) CellSyncQueue struct alignas(32) CellSyncQueue
{ {
struct alignas(8) ctrl_t struct ctrl_t
{ {
union union
{ {
@ -290,7 +290,7 @@ enum CellSyncQueueDirection : u32 // CellSyncLFQueueDirection
struct alignas(128) CellSyncLFQueue struct alignas(128) CellSyncLFQueue
{ {
struct alignas(8) pop1_t struct pop1_t
{ {
be_t<u16> m_h1; be_t<u16> m_h1;
be_t<u16> m_h2; be_t<u16> m_h2;
@ -303,13 +303,13 @@ struct alignas(128) CellSyncLFQueue
be_t<u16> pack; be_t<u16> pack;
}; };
struct alignas(4) pop3_t struct pop3_t
{ {
be_t<u16> m_h1; be_t<u16> m_h1;
be_t<u16> m_h2; be_t<u16> m_h2;
}; };
struct alignas(8) push1_t struct push1_t
{ {
be_t<u16> m_h5; be_t<u16> m_h5;
be_t<u16> m_h6; be_t<u16> m_h6;
@ -322,7 +322,7 @@ struct alignas(128) CellSyncLFQueue
be_t<u16> pack; be_t<u16> pack;
}; };
struct alignas(4) push3_t struct push3_t
{ {
be_t<u16> m_h5; be_t<u16> m_h5;
be_t<u16> m_h6; be_t<u16> m_h6;

View file

@ -254,10 +254,10 @@ void atomic_wait::list<Max, T...>::wait(atomic_wait_timeout timeout)
template <typename T, std::size_t Size = sizeof(T)> template <typename T, std::size_t Size = sizeof(T)>
struct atomic_storage struct atomic_storage
{ {
static_assert(sizeof(T) <= 16 && sizeof(T) == alignof(T), "atomic_storage<> error: invalid type");
/* First part: Non-MSVC intrinsics */ /* First part: Non-MSVC intrinsics */
using type = get_uint_t<sizeof(T)>;
#ifndef _MSC_VER #ifndef _MSC_VER
#if defined(__ATOMIC_HLE_ACQUIRE) && defined(__ATOMIC_HLE_RELEASE) #if defined(__ATOMIC_HLE_ACQUIRE) && defined(__ATOMIC_HLE_RELEASE)
@ -270,19 +270,19 @@ struct atomic_storage
static inline bool compare_exchange(T& dest, T& comp, T exch) static inline bool compare_exchange(T& dest, T& comp, T exch)
{ {
return __atomic_compare_exchange(&dest, &comp, &exch, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return __atomic_compare_exchange(reinterpret_cast<type*>(&dest), reinterpret_cast<type*>(&comp), reinterpret_cast<type*>(&exch), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
} }
static inline bool compare_exchange_hle_acq(T& dest, T& comp, T exch) static inline bool compare_exchange_hle_acq(T& dest, T& comp, T exch)
{ {
static_assert(sizeof(T) == 4 || sizeof(T) == 8); static_assert(sizeof(T) == 4 || sizeof(T) == 8);
return __atomic_compare_exchange(&dest, &comp, &exch, false, s_hle_ack, s_hle_ack); return __atomic_compare_exchange(reinterpret_cast<type*>(&dest), reinterpret_cast<type*>(&comp), reinterpret_cast<type*>(&exch), false, s_hle_ack, s_hle_ack);
} }
static inline T load(const T& dest) static inline T load(const T& dest)
{ {
T result; T result;
__atomic_load(&dest, &result, __ATOMIC_SEQ_CST); __atomic_load(reinterpret_cast<const type*>(&dest), reinterpret_cast<type*>(&result), __ATOMIC_SEQ_CST);
return result; return result;
} }
@ -293,13 +293,13 @@ struct atomic_storage
static inline void release(T& dest, T value) static inline void release(T& dest, T value)
{ {
__atomic_store(&dest, &value, __ATOMIC_RELEASE); __atomic_store(reinterpret_cast<type*>(&dest), reinterpret_cast<type*>(&value), __ATOMIC_RELEASE);
} }
static inline T exchange(T& dest, T value) static inline T exchange(T& dest, T value)
{ {
T result; T result;
__atomic_exchange(&dest, &value, &result, __ATOMIC_SEQ_CST); __atomic_exchange(reinterpret_cast<type*>(&dest), reinterpret_cast<type*>(&value), reinterpret_cast<type*>(&result), __ATOMIC_SEQ_CST);
return result; return result;
} }
@ -909,6 +909,7 @@ struct atomic_storage<T, 16> : atomic_storage<T, 0>
static inline T exchange(T& dest, T value) static inline T exchange(T& dest, T value)
{ {
__atomic_thread_fence(__ATOMIC_ACQ_REL);
return std::bit_cast<T>(__sync_lock_test_and_set(reinterpret_cast<u128*>(&dest), std::bit_cast<u128>(value))); return std::bit_cast<T>(__sync_lock_test_and_set(reinterpret_cast<u128*>(&dest), std::bit_cast<u128>(value)));
} }
@ -929,7 +930,7 @@ struct atomic_storage<T, 16> : atomic_storage<T, 0>
}; };
// Atomic type with lock-free and standard layout guarantees (and appropriate limitations) // Atomic type with lock-free and standard layout guarantees (and appropriate limitations)
template <typename T, std::size_t Align = alignof(T)> template <typename T, std::size_t Align = sizeof(T)>
class atomic_t class atomic_t
{ {
protected: protected:
@ -937,11 +938,22 @@ protected:
using ptr_rt = std::conditional_t<std::is_pointer_v<type>, ullong, type>; using ptr_rt = std::conditional_t<std::is_pointer_v<type>, ullong, type>;
static_assert(alignof(type) == sizeof(type), "atomic_t<> error: unexpected alignment, use alignas() if necessary"); static_assert((Align & (Align - 1)) == 0, "atomic_t<> error: unexpected Align parameter (not power of 2).");
static_assert(Align % sizeof(type) == 0, "atomic_t<> error: invalid type, must be power of 2.");
static_assert(sizeof(type) <= 16, "atomic_t<> error: invalid type, too big (max supported size is 16).");
static_assert(Align >= sizeof(type), "atomic_t<> error: bad args, specify bigger alignment if necessary.");
static_assert(std::is_trivially_copyable_v<type>);
static_assert(std::is_copy_constructible_v<type>);
static_assert(std::is_move_constructible_v<type>);
static_assert(std::is_copy_assignable_v<type>);
static_assert(std::is_move_assignable_v<type>);
alignas(Align) type m_data; alignas(Align) type m_data;
public: public:
static constexpr std::size_t align = Align;
atomic_t() noexcept = default; atomic_t() noexcept = default;
atomic_t(const atomic_t&) = delete; atomic_t(const atomic_t&) = delete;