2
0
mirror of https://github.com/boostorg/atomic.git synced 2026-01-19 04:02:09 +00:00
Files
atomic/test/lockfree.cpp
Andrey Semashev 37c2b67324 Added support for MSVC ARM64EC target.
ARM64EC is similar to ARM64 in that the binary will run natively on
ARM64 CPUs and therefore supports all ARM64 intrinsics. The difference
is that it also supports AMD64 intrinsics (and therefore defines _M_AMD64
and _M_X64), which will be emulated by an implicitly linked library.
ARM64EC also changes ABI compared to ARM64, but it doesn't affect
Boost.Atomic.

Changed predefined macro checks in order to use msvc_arm backend for
ARM64EC instead of msvc_x86. The benefit is that msvc_arm uses memory
order-aware intrinsics instead of the full-fence ones on x86. The
downside is that 128-bit atomics won't be available (for now).

Also define BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH for ARM/ARM64
on Windows.
2025-06-09 02:22:34 +03:00

257 lines
9.2 KiB
C++

// Copyright (c) 2011 Helge Bahmann
// Copyright (c) 2020 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Verify that definition of the "LOCK_FREE" macros and the
// "is_lock_free" members is consistent and matches expectations.
// Also, if any operation is lock-free, then the platform
// implementation must provide overridden fence implementations.
#include <boost/atomic.hpp>
#include <iostream>
#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>
#include "aligned_object.hpp"
#if defined(BOOST_MSVC)
// conditional expression is constant
#pragma warning(disable: 4127)
#endif
static const char* const lock_free_level[] =
{
"never",
"sometimes",
"always"
};
template< typename T >
void verify_lock_free(const char* type_name, int lock_free_macro_val, int lock_free_expect)
{
BOOST_TEST(lock_free_macro_val >= 0 && lock_free_macro_val <= 2);
BOOST_TEST_EQ(lock_free_macro_val, lock_free_expect);
boost::atomic<T> value;
if (lock_free_macro_val == 0)
BOOST_TEST(!value.is_lock_free());
if (lock_free_macro_val == 2)
BOOST_TEST(value.is_lock_free());
BOOST_TEST_EQ(boost::atomic<T>::is_always_lock_free, (lock_free_expect == 2));
std::cout << "atomic<" << type_name << "> is " << lock_free_level[lock_free_macro_val] << " lock free\n";
// atomic<T> may use larger storage than sizeof(T) to achieve lock-free property. In this case atomic_ref<T> may not be lock-free.
if (sizeof(boost::atomic<T>) == sizeof(T))
{
aligned_object<T, boost::atomic_ref<T>::required_alignment> object;
boost::atomic_ref<T> ref(object.get());
BOOST_TEST_EQ(ref.is_lock_free(), value.is_lock_free());
BOOST_TEST_EQ(boost::atomic_ref<T>::is_always_lock_free, boost::atomic<T>::is_always_lock_free);
}
}
#if (defined(__GNUC__) || defined(__SUNPRO_CC)) && defined(__i386__)
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) ||\
defined(__i586__) || defined(__i686__) || defined(__SSE__)
#define EXPECT_LLONG_LOCK_FREE 2
#else
#define EXPECT_LLONG_LOCK_FREE 0
#endif
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif (defined(__GNUC__) || defined(__SUNPRO_CC)) && defined(__x86_64__)
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#define EXPECT_LLONG_LOCK_FREE 2
#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)
#define EXPECT_INT128_LOCK_FREE 2
#else
#define EXPECT_INT128_LOCK_FREE 0
#endif
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__))
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_CHAR16_T_LOCK_FREE 2
#define EXPECT_CHAR32_T_LOCK_FREE 2
#define EXPECT_WCHAR_T_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#if defined(__powerpc64__)
#define EXPECT_LLONG_LOCK_FREE 2
#else
#define EXPECT_LLONG_LOCK_FREE 0
#endif
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif defined(__GNUC__) && defined(__alpha__)
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_CHAR16_T_LOCK_FREE 2
#define EXPECT_CHAR32_T_LOCK_FREE 2
#define EXPECT_WCHAR_T_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#define EXPECT_LLONG_LOCK_FREE 2
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif defined(__GNUC__) && defined(__aarch64__)
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#define EXPECT_LLONG_LOCK_FREE 2
#define EXPECT_INT128_LOCK_FREE 2
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif defined(__GNUC__) && defined(__arm__) &&\
(\
(defined(__ARM_ARCH) && __ARM_ARCH >= 6) ||\
defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) ||\
defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) ||\
defined(__ARM_ARCH_6ZK__) ||\
defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) ||\
defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) ||\
defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7S__) ||\
defined(__ARM_ARCH_8A__)\
)
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#if !(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6Z__)\
|| ((defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__)) && defined(__thumb__)) || defined(__ARM_ARCH_7M__))
#define EXPECT_LLONG_LOCK_FREE 2
#else
#define EXPECT_LLONG_LOCK_FREE 0
#endif
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif defined(__linux__) && defined(__arm__)
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#define EXPECT_LLONG_LOCK_FREE 0
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif (defined(__GNUC__) || defined(__SUNPRO_CC)) && (defined(__sparcv8plus) || defined(__sparc_v9__))
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#define EXPECT_LLONG_LOCK_FREE 2
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#elif defined(BOOST_USE_WINDOWS_H) || defined(_WIN32_CE) || defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#define EXPECT_CHAR_LOCK_FREE 2
#define EXPECT_SHORT_LOCK_FREE 2
#define EXPECT_INT_LOCK_FREE 2
#define EXPECT_LONG_LOCK_FREE 2
#if defined(_WIN64) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(_M_AMD64) || defined(_M_IA64) || (_MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC)))
#define EXPECT_LLONG_LOCK_FREE 2
#else
#define EXPECT_LLONG_LOCK_FREE 0
#endif
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 2
#define EXPECT_BOOL_LOCK_FREE 2
#else
#define EXPECT_CHAR_LOCK_FREE 0
#define EXPECT_SHORT_LOCK_FREE 0
#define EXPECT_INT_LOCK_FREE 0
#define EXPECT_LONG_LOCK_FREE 0
#define EXPECT_LLONG_LOCK_FREE 0
#define EXPECT_INT128_LOCK_FREE 0
#define EXPECT_POINTER_LOCK_FREE 0
#define EXPECT_BOOL_LOCK_FREE 0
#endif
int main(int, char *[])
{
verify_lock_free<char>("char", BOOST_ATOMIC_CHAR_LOCK_FREE, EXPECT_CHAR_LOCK_FREE);
verify_lock_free<short>("short", BOOST_ATOMIC_SHORT_LOCK_FREE, EXPECT_SHORT_LOCK_FREE);
verify_lock_free<int>("int", BOOST_ATOMIC_INT_LOCK_FREE, EXPECT_INT_LOCK_FREE);
verify_lock_free<long>("long", BOOST_ATOMIC_LONG_LOCK_FREE, EXPECT_LONG_LOCK_FREE);
#ifdef BOOST_HAS_LONG_LONG
verify_lock_free<long long>("long long", BOOST_ATOMIC_LLONG_LOCK_FREE, EXPECT_LLONG_LOCK_FREE);
#endif
#ifdef BOOST_HAS_INT128
verify_lock_free<boost::int128_type>("int128", BOOST_ATOMIC_INT128_LOCK_FREE, EXPECT_INT128_LOCK_FREE);
#endif
verify_lock_free<void *>("void *", BOOST_ATOMIC_POINTER_LOCK_FREE, EXPECT_SHORT_LOCK_FREE);
verify_lock_free<bool>("bool", BOOST_ATOMIC_BOOL_LOCK_FREE, EXPECT_BOOL_LOCK_FREE);
#ifndef BOOST_ATOMIC_NO_FLOATING_POINT
verify_lock_free<float>("float", BOOST_ATOMIC_FLOAT_LOCK_FREE,
sizeof(float) == 1 ? EXPECT_CHAR_LOCK_FREE : (sizeof(float) == 2 ? EXPECT_SHORT_LOCK_FREE :
(sizeof(float) <= 4 ? EXPECT_INT_LOCK_FREE : (sizeof(float) <= 8 ? EXPECT_LLONG_LOCK_FREE : (sizeof(float) <= 16 ? EXPECT_INT128_LOCK_FREE : 0)))));
verify_lock_free<double>("double", BOOST_ATOMIC_DOUBLE_LOCK_FREE,
sizeof(double) == 1 ? EXPECT_CHAR_LOCK_FREE : (sizeof(double) == 2 ? EXPECT_SHORT_LOCK_FREE :
(sizeof(double) <= 4 ? EXPECT_INT_LOCK_FREE : (sizeof(double) <= 8 ? EXPECT_LLONG_LOCK_FREE : (sizeof(double) <= 16 ? EXPECT_INT128_LOCK_FREE : 0)))));
verify_lock_free<long double>("long double", BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE,
sizeof(long double) == 1 ? EXPECT_CHAR_LOCK_FREE : (sizeof(long double) == 2 ? EXPECT_SHORT_LOCK_FREE :
(sizeof(long double) <= 4 ? EXPECT_INT_LOCK_FREE : (sizeof(long double) <= 8 ? EXPECT_LLONG_LOCK_FREE : (sizeof(long double) <= 16 ? EXPECT_INT128_LOCK_FREE : 0)))));
#if defined(BOOST_HAS_INT128) && defined(BOOST_HAS_FLOAT128)
verify_lock_free<boost::float128_type>("float128", BOOST_ATOMIC_INT128_LOCK_FREE, EXPECT_INT128_LOCK_FREE);
#endif
#endif // BOOST_ATOMIC_NO_FLOATING_POINT
bool any_lock_free =
BOOST_ATOMIC_CHAR_LOCK_FREE > 0 ||
BOOST_ATOMIC_SHORT_LOCK_FREE > 0 ||
BOOST_ATOMIC_INT_LOCK_FREE > 0 ||
BOOST_ATOMIC_LONG_LOCK_FREE > 0 ||
BOOST_ATOMIC_LLONG_LOCK_FREE > 0 ||
BOOST_ATOMIC_BOOL_LOCK_FREE > 0;
BOOST_TEST(!any_lock_free || BOOST_ATOMIC_THREAD_FENCE > 0);
return boost::report_errors();
}