Bug 1363426 - part 1 - remove #ifdeffery in Atomics.h; r=erahm

Every platform where we use GCC has <atomic>, so there's no need to use
GCC-specific __sync* intrinsics anymore.  The <atomic> header may
generate better code for several operations, as well.
This commit is contained in:
Nathan Froyd 2017-05-10 09:58:28 -04:00
Родитель d676a8001e
Коммит fe42aa0b9d
1 изменённых файлов: 1 добавлений и 212 удалений

Просмотреть файл

@ -164,9 +164,6 @@ enum MemoryOrdering {
} // namespace mozilla
// Build up the underlying intrinsics.
#ifdef MOZ_HAVE_CXX11_ATOMICS
#include <atomic>
namespace mozilla {
@ -326,214 +323,6 @@ struct ToStorageTypeArgument
static constexpr T convert (T aT) { return aT; }
};
} // namespace detail
} // namespace mozilla
#elif defined(__GNUC__)
namespace mozilla {
namespace detail {
/*
* The __sync_* family of intrinsics is documented here:
*
* http://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Atomic-Builtins.html
*
* While these intrinsics are deprecated in favor of the newer __atomic_*
* family of intrincs:
*
* http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/_005f_005fatomic-Builtins.html
*
* any GCC version that supports the __atomic_* intrinsics will also support
* the <atomic> header and so will be handled above. We provide a version of
* atomics using the __sync_* intrinsics to support older versions of GCC.
*
* All __sync_* intrinsics that we use below act as full memory barriers, for
* both compiler and hardware reordering, except for __sync_lock_test_and_set,
* which is a only an acquire barrier. When we call __sync_lock_test_and_set,
* we add a barrier above it as appropriate.
*/
template<MemoryOrdering Order> struct Barrier;
/*
* Some processors (in particular, x86) don't require quite so many calls to
* __sync_sychronize as our specializations of Barrier produce. If
* performance turns out to be an issue, defining these specializations
* on a per-processor basis would be a good first tuning step.
*/
template<>
struct Barrier<Relaxed>
{
static void beforeLoad() {}
static void afterLoad() {}
static void beforeStore() {}
static void afterStore() {}
};
template<>
struct Barrier<ReleaseAcquire>
{
static void beforeLoad() {}
static void afterLoad() { __sync_synchronize(); }
static void beforeStore() { __sync_synchronize(); }
static void afterStore() {}
};
template<>
struct Barrier<SequentiallyConsistent>
{
static void beforeLoad() { __sync_synchronize(); }
static void afterLoad() { __sync_synchronize(); }
static void beforeStore() { __sync_synchronize(); }
static void afterStore() { __sync_synchronize(); }
};
template<typename T, bool TIsEnum = IsEnum<T>::value>
struct AtomicStorageType
{
// For non-enums, just use the type directly.
typedef T Type;
};
template<typename T>
struct AtomicStorageType<T, true>
: Conditional<sizeof(T) == 4, uint32_t, uint64_t>
{
static_assert(sizeof(T) == 4 || sizeof(T) == 8,
"wrong type computed in conditional above");
};
template<typename T, MemoryOrdering Order>
struct IntrinsicMemoryOps
{
typedef typename AtomicStorageType<T>::Type ValueType;
static T load(const ValueType& aPtr)
{
Barrier<Order>::beforeLoad();
T val = T(aPtr);
Barrier<Order>::afterLoad();
return val;
}
static void store(ValueType& aPtr, T aVal)
{
Barrier<Order>::beforeStore();
aPtr = ValueType(aVal);
Barrier<Order>::afterStore();
}
static T exchange(ValueType& aPtr, T aVal)
{
// __sync_lock_test_and_set is only an acquire barrier; loads and stores
// can't be moved up from after to before it, but they can be moved down
// from before to after it. We may want a stricter ordering, so we need
// an explicit barrier.
Barrier<Order>::beforeStore();
return T(__sync_lock_test_and_set(&aPtr, ValueType(aVal)));
}
static bool compareExchange(ValueType& aPtr, T aOldVal, T aNewVal)
{
return __sync_bool_compare_and_swap(&aPtr, ValueType(aOldVal), ValueType(aNewVal));
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub
: public IntrinsicMemoryOps<T, Order>
{
typedef IntrinsicMemoryOps<T, Order> Base;
typedef typename Base::ValueType ValueType;
static T add(ValueType& aPtr, T aVal)
{
return T(__sync_fetch_and_add(&aPtr, ValueType(aVal)));
}
static T sub(ValueType& aPtr, T aVal)
{
return T(__sync_fetch_and_sub(&aPtr, ValueType(aVal)));
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicAddSub<T*, Order>
: public IntrinsicMemoryOps<T*, Order>
{
typedef IntrinsicMemoryOps<T*, Order> Base;
typedef typename Base::ValueType ValueType;
/*
* The reinterpret_casts are needed so that
* __sync_fetch_and_{add,sub} will properly type-check.
*
* Also, these functions do not provide standard semantics for
* pointer types, so we need to adjust the addend.
*/
static ValueType add(ValueType& aPtr, ptrdiff_t aVal)
{
ValueType amount = reinterpret_cast<ValueType>(aVal * sizeof(T));
return __sync_fetch_and_add(&aPtr, amount);
}
static ValueType sub(ValueType& aPtr, ptrdiff_t aVal)
{
ValueType amount = reinterpret_cast<ValueType>(aVal * sizeof(T));
return __sync_fetch_and_sub(&aPtr, amount);
}
};
template<typename T, MemoryOrdering Order>
struct IntrinsicIncDec : public IntrinsicAddSub<T, Order>
{
typedef IntrinsicAddSub<T, Order> Base;
typedef typename Base::ValueType ValueType;
static T inc(ValueType& aPtr) { return Base::add(aPtr, 1); }
static T dec(ValueType& aPtr) { return Base::sub(aPtr, 1); }
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics : public IntrinsicIncDec<T, Order>
{
static T or_( T& aPtr, T aVal) { return __sync_fetch_and_or(&aPtr, aVal); }
static T xor_(T& aPtr, T aVal) { return __sync_fetch_and_xor(&aPtr, aVal); }
static T and_(T& aPtr, T aVal) { return __sync_fetch_and_and(&aPtr, aVal); }
};
template<typename T, MemoryOrdering Order>
struct AtomicIntrinsics<T*, Order> : public IntrinsicIncDec<T*, Order>
{
};
template<typename T, bool TIsEnum = IsEnum<T>::value>
struct ToStorageTypeArgument
{
typedef typename AtomicStorageType<T>::Type ResultType;
static constexpr ResultType convert (T aT) { return ResultType(aT); }
};
template<typename T>
struct ToStorageTypeArgument<T, false>
{
static constexpr T convert (T aT) { return aT; }
};
} // namespace detail
} // namespace mozilla
#else
# error "Atomic compiler intrinsics are not supported on your platform"
#endif
namespace mozilla {
namespace detail {
template<typename T, MemoryOrdering Order>
class AtomicBase
{