brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.5 KiB · 2b3a3ca Raw
241 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef ATOMIC_HELPERS_H10#define ATOMIC_HELPERS_H11 12#include <cassert>13#include <cstdint>14#include <cstddef>15#include <type_traits>16 17#include "test_macros.h"18 19#if defined(TEST_COMPILER_CLANG)20#  define TEST_ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE21#  define TEST_ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE22#  define TEST_ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE23#  define TEST_ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE24#  define TEST_ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE25#  define TEST_ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE26#elif defined(TEST_COMPILER_GCC)27#  define TEST_ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE28#  define TEST_ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE29#  define TEST_ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE30#  define TEST_ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE31#  define TEST_ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE32#  define TEST_ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE33#elif defined(TEST_COMPILER_MSVC)34// This is lifted from STL/stl/inc/atomic on github for the purposes of35// keeping the tests compiling for MSVC's STL. It's not a perfect solution36// but at least the tests will keep running.37//38// Note MSVC's STL never produces a type that is sometimes lock free, but not always lock free.39template <class T, size_t Size = sizeof(T)>40constexpr int msvc_is_lock_free_macro_value() {41  return (Size <= 8 && (Size & (Size - 1)) == 0) ? 2 : 0;42}43#  define TEST_ATOMIC_CHAR_LOCK_FREE ::msvc_is_lock_free_macro_value<char>()44#  define TEST_ATOMIC_SHORT_LOCK_FREE ::msvc_is_lock_free_macro_value<short>()45#  define TEST_ATOMIC_INT_LOCK_FREE ::msvc_is_lock_free_macro_value<int>()46#  define TEST_ATOMIC_LONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long>()47#  define TEST_ATOMIC_LLONG_LOCK_FREE ::msvc_is_lock_free_macro_value<long long>()48#  define TEST_ATOMIC_POINTER_LOCK_FREE ::msvc_is_lock_free_macro_value<void*>()49#else50#  error "Unknown compiler"51#endif52 53#ifdef TEST_COMPILER_CLANG54#  pragma clang diagnostic push55#  pragma clang diagnostic ignored "-Wc++11-extensions"56#endif57 58enum class LockFreeStatus : int { unknown = -1, never = 0, sometimes = 1, always = 2 };59 60// We should really be checking whether the alignment of T is greater-than-or-equal-to the alignment required61// for T to be atomic, but this is basically impossible to implement portably. Instead, we assume that any type62// aligned to at least its size is going to be atomic if there exists atomic operations for that size at all,63// which is true on most platforms. This technically reduces our test coverage in the sense that if a type has64// an alignment requirement less than its size but could still be made lockfree, LockFreeStatusInfo will report65// that we don't know whether it is lockfree or not.66#define COMPARE_TYPES(T, FundamentalT) (sizeof(T) == sizeof(FundamentalT) && TEST_ALIGNOF(T) >= sizeof(T))67 68template <class T>69struct LockFreeStatusInfo {70  static const LockFreeStatus value = LockFreeStatus(71      COMPARE_TYPES(T, char)72          ? TEST_ATOMIC_CHAR_LOCK_FREE73          : (COMPARE_TYPES(T, short)74                 ? TEST_ATOMIC_SHORT_LOCK_FREE75                 : (COMPARE_TYPES(T, int)76                        ? TEST_ATOMIC_INT_LOCK_FREE77                        : (COMPARE_TYPES(T, long)78                               ? TEST_ATOMIC_LONG_LOCK_FREE79                               : (COMPARE_TYPES(T, long long)80                                      ? TEST_ATOMIC_LLONG_LOCK_FREE81                                      : (COMPARE_TYPES(T, void*) ? TEST_ATOMIC_POINTER_LOCK_FREE : -1))))));82 83  static const bool status_known = LockFreeStatusInfo::value != LockFreeStatus::unknown;84};85 86#undef COMPARE_TYPES87 88// This doesn't work in C++03 due to issues with scoped enumerations. Just disable the test.89#if TEST_STD_VER >= 1190static_assert(LockFreeStatusInfo<char>::status_known, "");91static_assert(LockFreeStatusInfo<short>::status_known, "");92static_assert(LockFreeStatusInfo<int>::status_known, "");93static_assert(LockFreeStatusInfo<long>::status_known, "");94static_assert(LockFreeStatusInfo<void*>::status_known, "");95 96// long long is a bit funky: on some platforms, its alignment is 4 bytes but its size is97// 8 bytes. In that case, atomics may or may not be lockfree based on their address.98static_assert(alignof(long long) == sizeof(long long) ? LockFreeStatusInfo<long long>::status_known : true, "");99 100// Those should always be lock free: hardcode some expected values to make sure our tests are actually101// testing something meaningful.102static_assert(LockFreeStatusInfo<char>::value == LockFreeStatus::always, "");103static_assert(LockFreeStatusInfo<short>::value == LockFreeStatus::always, "");104static_assert(LockFreeStatusInfo<int>::value == LockFreeStatus::always, "");105#endif106 107// These macros are somewhat suprising to use, since they take the values 0, 1, or 2.108// To make the tests clearer, get rid of them in preference of LockFreeStatusInfo.109#undef TEST_ATOMIC_CHAR_LOCK_FREE110#undef TEST_ATOMIC_SHORT_LOCK_FREE111#undef TEST_ATOMIC_INT_LOCK_FREE112#undef TEST_ATOMIC_LONG_LOCK_FREE113#undef TEST_ATOMIC_LLONG_LOCK_FREE114#undef TEST_ATOMIC_POINTER_LOCK_FREE115 116#ifdef TEST_COMPILER_CLANG117#  pragma clang diagnostic pop118#endif119 120struct UserAtomicType {121  int i;122 123  explicit UserAtomicType(int d = 0) TEST_NOEXCEPT : i(d) {}124 125  friend bool operator==(const UserAtomicType& x, const UserAtomicType& y) { return x.i == y.i; }126};127 128/*129 130Enable these once we have P0528131 132struct WeirdUserAtomicType133{134    char i, j, k; // the 3 chars of doom135 136    explicit WeirdUserAtomicType(int d = 0) TEST_NOEXCEPT : i(d) {}137 138    friend bool operator==(const WeirdUserAtomicType& x, const WeirdUserAtomicType& y)139    { return x.i == y.i; }140};141 142struct PaddedUserAtomicType143{144    char i; int j; // probably lock-free?145 146    explicit PaddedUserAtomicType(int d = 0) TEST_NOEXCEPT : i(d) {}147 148    friend bool operator==(const PaddedUserAtomicType& x, const PaddedUserAtomicType& y)149    { return x.i == y.i; }150};151 152*/153 154struct LargeUserAtomicType {155  int a[128]; /* decidedly not lock-free */156 157  LargeUserAtomicType(int d = 0) TEST_NOEXCEPT {158    for (auto&& e : a)159      e = d++;160  }161 162  friend bool operator==(LargeUserAtomicType const& x, LargeUserAtomicType const& y) TEST_NOEXCEPT {163    for (int i = 0; i < 128; ++i)164      if (x.a[i] != y.a[i])165        return false;166    return true;167  }168};169 170template <template <class TestArg> class TestFunctor>171struct TestEachIntegralType {172  void operator()() const {173    TestFunctor<char>()();174    TestFunctor<signed char>()();175    TestFunctor<unsigned char>()();176    TestFunctor<short>()();177    TestFunctor<unsigned short>()();178    TestFunctor<int>()();179    TestFunctor<unsigned int>()();180    TestFunctor<long>()();181    TestFunctor<unsigned long>()();182    TestFunctor<long long>()();183    TestFunctor<unsigned long long>()();184    TestFunctor<wchar_t>()();185#if TEST_STD_VER > 17 && defined(__cpp_char8_t)186    TestFunctor<char8_t>()();187#endif188    TestFunctor<char16_t>()();189    TestFunctor<char32_t>()();190    TestFunctor<std::int8_t>()();191    TestFunctor<std::uint8_t>()();192    TestFunctor<std::int16_t>()();193    TestFunctor<std::uint16_t>()();194    TestFunctor<std::int32_t>()();195    TestFunctor<std::uint32_t>()();196    TestFunctor<std::int64_t>()();197    TestFunctor<std::uint64_t>()();198  }199};200 201template <template <class TestArg> class TestFunctor>202struct TestEachFloatingPointType {203  void operator()() const {204    TestFunctor<float>()();205    TestFunctor<double>()();206    TestFunctor<long double>()();207  }208};209 210template <template <class TestArg> class TestFunctor>211struct TestEachPointerType {212  void operator()() const {213    TestFunctor<int*>()();214    TestFunctor<const int*>()();215  }216};217 218template <template <class TestArg> class TestFunctor>219struct TestEachAtomicType {220  void operator()() const {221    TestEachIntegralType<TestFunctor>()();222    TestEachPointerType<TestFunctor>()();223    TestFunctor<UserAtomicType>()();224    /*225            Note: These aren't going to be lock-free,226            so some libatomic.a is necessary.227        */228    TestFunctor<LargeUserAtomicType>()();229    /*230    Enable these once we have P0528231 232        TestFunctor<PaddedUserAtomicType>()();233        TestFunctor<WeirdUserAtomicType>()();234*/235    TestFunctor<float>()();236    TestFunctor<double>()();237  }238};239 240#endif // ATOMIC_HELPERS_H241