bts/btr/btc support improved

This commit is contained in:
Nekotekina 2016-08-10 15:48:34 +03:00
parent 130f7905ba
commit 8c8242345e
2 changed files with 171 additions and 10 deletions

View File

@ -174,7 +174,7 @@ struct atomic_storage
} }
}; };
/* The rest: ugly MSVC intrinsics + possibly __asm__ implementations (TODO) */ /* The rest: ugly MSVC intrinsics + inline asm implementations */
template<typename T> template<typename T>
struct atomic_storage<T, 1> : atomic_storage<T, 0> struct atomic_storage<T, 1> : atomic_storage<T, 0>
@ -297,6 +297,27 @@ struct atomic_storage<T, 2> : atomic_storage<T, 0>
short r = _InterlockedDecrement16((volatile short*)&dest); short r = _InterlockedDecrement16((volatile short*)&dest);
return (T&)r; return (T&)r;
} }
#else
static inline bool bts(T& dest, uint bit)
{
bool result;
__asm__("lock btsw %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
static inline bool btr(T& dest, uint bit)
{
bool result;
__asm__("lock btrw %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
static inline bool btc(T& dest, uint bit)
{
bool result;
__asm__("lock btcw %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
#endif #endif
}; };
@ -375,6 +396,27 @@ struct atomic_storage<T, 4> : atomic_storage<T, 0>
{ {
return _interlockedbittestandreset((volatile long*)&dest, bit) != 0; return _interlockedbittestandreset((volatile long*)&dest, bit) != 0;
} }
#else
static inline bool bts(T& dest, uint bit)
{
bool result;
__asm__("lock btsl %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
static inline bool btr(T& dest, uint bit)
{
bool result;
__asm__("lock btrl %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
static inline bool btc(T& dest, uint bit)
{
bool result;
__asm__("lock btcl %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
#endif #endif
}; };
@ -453,6 +495,27 @@ struct atomic_storage<T, 8> : atomic_storage<T, 0>
{ {
return _interlockedbittestandreset64((volatile llong*)&dest, bit) != 0; return _interlockedbittestandreset64((volatile llong*)&dest, bit) != 0;
} }
#else
static inline bool bts(T& dest, uint bit)
{
bool result;
__asm__("lock btsq %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
static inline bool btr(T& dest, uint bit)
{
bool result;
__asm__("lock btrq %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
static inline bool btc(T& dest, uint bit)
{
bool result;
__asm__("lock btcq %2, %0\n" "setc %1" : "+m" (dest), "=r" (result) : "Ir" (bit) : "cc");
return result;
}
#endif #endif
}; };
@ -490,6 +553,8 @@ struct atomic_storage<T, 16> : atomic_storage<T, 0>
return *(T*)+cmp; return *(T*)+cmp;
} }
#endif #endif
// TODO
}; };
template<typename T1, typename T2, typename> template<typename T1, typename T2, typename>
@ -642,7 +707,7 @@ struct atomic_test_and_set
{ {
bool operator()(T1& lhs, const T2& rhs) const bool operator()(T1& lhs, const T2& rhs) const
{ {
return lhs.test_and_set(rhs); return test_and_set(lhs, rhs);
} }
}; };
@ -659,7 +724,7 @@ struct atomic_test_and_reset
{ {
bool operator()(T1& lhs, const T2& rhs) const bool operator()(T1& lhs, const T2& rhs) const
{ {
return lhs.test_and_reset(rhs); return test_and_reset(lhs, rhs);
} }
}; };
@ -676,7 +741,7 @@ struct atomic_test_and_complement
{ {
bool operator()(T1& lhs, const T2& rhs) const bool operator()(T1& lhs, const T2& rhs) const
{ {
return lhs.test_and_complement(rhs); return test_and_complement(lhs, rhs);
} }
}; };

View File

@ -199,32 +199,32 @@ struct bs_base
return (shift(lhs) & static_cast<under>(rhs)) != 0; return (shift(lhs) & static_cast<under>(rhs)) != 0;
} }
friend constexpr bool test_and_set(type& lhs, type rhs) friend bool test_and_set(type& lhs, type rhs)
{ {
return test_and_set(reinterpret_cast<under&>(lhs), static_cast<under>(rhs)); return test_and_set(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
} }
friend constexpr bool test_and_set(type& lhs, T rhs) friend bool test_and_set(type& lhs, T rhs)
{ {
return test_and_set(reinterpret_cast<under&>(lhs), shift(rhs)); return test_and_set(reinterpret_cast<under&>(lhs), shift(rhs));
} }
friend constexpr bool test_and_reset(type& lhs, type rhs) friend bool test_and_reset(type& lhs, type rhs)
{ {
return test_and_reset(reinterpret_cast<under&>(lhs), static_cast<under>(rhs)); return test_and_reset(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
} }
friend constexpr bool test_and_reset(type& lhs, T rhs) friend bool test_and_reset(type& lhs, T rhs)
{ {
return test_and_reset(reinterpret_cast<under&>(lhs), shift(rhs)); return test_and_reset(reinterpret_cast<under&>(lhs), shift(rhs));
} }
friend constexpr bool test_and_complement(type& lhs, type rhs) friend bool test_and_complement(type& lhs, type rhs)
{ {
return test_and_complement(reinterpret_cast<under&>(lhs), static_cast<under>(rhs)); return test_and_complement(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
} }
friend constexpr bool test_and_complement(type& lhs, T rhs) friend bool test_and_complement(type& lhs, T rhs)
{ {
return test_and_complement(reinterpret_cast<under&>(lhs), shift(rhs)); return test_and_complement(reinterpret_cast<under&>(lhs), shift(rhs));
} }
@ -461,6 +461,8 @@ struct atomic_test_and_set<BS, T, void_t<decltype(T::__bitset_enum_max), std::en
return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value))); return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
} }
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op; static constexpr auto atomic_op = &_op;
}; };
@ -474,6 +476,8 @@ struct atomic_test_and_reset<BS, T, void_t<decltype(T::__bitset_enum_max), std::
return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value))); return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
} }
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op; static constexpr auto atomic_op = &_op;
}; };
@ -487,6 +491,53 @@ struct atomic_test_and_complement<BS, T, void_t<decltype(T::__bitset_enum_max),
return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value))); return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
} }
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_set<T, T, void_t<decltype(T::__bitset_set_type)>>
{
using under = std::underlying_type_t<T>;
static inline bool _op(T& left, T value)
{
return atomic_storage<under>::test_and_set(reinterpret_cast<under&>(left), static_cast<under>(value));
}
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_reset<T, T, void_t<decltype(T::__bitset_set_type)>>
{
using under = std::underlying_type_t<T>;
static inline bool _op(T& left, T value)
{
return atomic_storage<under>::test_and_reset(reinterpret_cast<under&>(left), static_cast<under>(value));
}
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_complement<T, T, void_t<decltype(T::__bitset_set_type)>>
{
using under = std::underlying_type_t<T>;
static inline bool _op(T& left, T value)
{
return atomic_storage<under>::test_and_complement(reinterpret_cast<under&>(left), static_cast<under>(value));
}
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op; static constexpr auto atomic_op = &_op;
}; };
@ -634,3 +685,48 @@ struct atomic_xor<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std:
static constexpr auto op_fetch = &op2; static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2; static constexpr auto atomic_op = &op2;
}; };
template<typename T>
struct atomic_test_and_set<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
{
using under = std::underlying_type_t<T>;
static inline bool _op(T& left, T value)
{
return atomic_storage<under>::test_and_set(reinterpret_cast<under&>(left), static_cast<under>(value));
}
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_reset<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
{
using under = std::underlying_type_t<T>;
static inline bool _op(T& left, T value)
{
return atomic_storage<under>::test_and_reset(reinterpret_cast<under&>(left), static_cast<under>(value));
}
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_complement<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
{
using under = std::underlying_type_t<T>;
static inline bool _op(T& left, T value)
{
return atomic_storage<under>::test_and_complement(reinterpret_cast<under&>(left), static_cast<under>(value));
}
static constexpr auto fetch_op = &_op;
static constexpr auto op_fetch = &_op;
static constexpr auto atomic_op = &_op;
};