Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix atomic_ref<16 bytes>::is_always_lock_free #4478

Merged
merged 14 commits into from
Mar 19, 2024
Merged
15 changes: 10 additions & 5 deletions stl/inc/atomic
Original file line number Diff line number Diff line change
Expand Up @@ -1656,7 +1656,7 @@ _INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= 2 * sizeof(void*)
#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv
template <size_t _TypeSize>
_INLINE_VAR constexpr bool _Is_always_lock_free = _TypeSize <= sizeof(void*);
#endif // _ATOMIC_HAS_DCAS
#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^
#endif // ^^^ break ABI ^^^

template <class _Ty, bool _Is_lock_free = _Is_always_lock_free<sizeof(_Ty)>>
Expand Down Expand Up @@ -2179,7 +2179,7 @@ public:
return sizeof(_Ty) <= 2 * sizeof(void*);
#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv
return sizeof(_Ty) <= sizeof(void*) || (sizeof(_Ty) <= 2 * sizeof(void*) && __std_atomic_has_cmpxchg16b());
#endif // _ATOMIC_HAS_DCAS
#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^
}
#endif // ^^^ break ABI ^^^

Expand Down Expand Up @@ -2343,11 +2343,16 @@ public:

atomic_ref& operator=(const atomic_ref&) = delete;

static constexpr bool is_always_lock_free = _Is_always_lock_free<sizeof(_Ty)>;

static constexpr bool _Is_potentially_lock_free =
sizeof(_Ty) <= 2 * sizeof(void*) && (sizeof(_Ty) & (sizeof(_Ty) - 1)) == 0;

static constexpr bool is_always_lock_free =
#if _ATOMIC_HAS_DCAS
_Is_potentially_lock_free;
#else // ^^^ _ATOMIC_HAS_DCAS / !_ATOMIC_HAS_DCAS vvv
_Is_potentially_lock_free && sizeof(_Ty) <= sizeof(void*);
#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^

static constexpr size_t required_alignment = _Is_potentially_lock_free ? sizeof(_Ty) : alignof(_Ty);

_NODISCARD bool is_lock_free() const noexcept {
Expand All @@ -2359,7 +2364,7 @@ public:
} else {
return __std_atomic_has_cmpxchg16b() != 0;
}
#endif // _ATOMIC_HAS_DCAS
#endif // ^^^ !_ATOMIC_HAS_DCAS ^^^
}

void store(const _Ty _Value) const noexcept {
Expand Down
3 changes: 3 additions & 0 deletions tests/std/tests/P0019R8_atomic_ref/env.lst
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_20_matrix.lst
RUNALL_CROSSLIST
PM_CL=""
PM_CL="/D_STD_ATOMIC_ALWAYS_USE_CMPXCHG16B=1"
21 changes: 21 additions & 0 deletions tests/std/tests/P0019R8_atomic_ref/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,26 @@ void test_incomplete_associated_class_all() { // COMPILE-ONLY
}
#endif // ^^^ no workaround ^^^

void test_gh_4472() {
struct two_pointers_t {
void* left;
void* right;
};

alignas(std::atomic_ref<two_pointers_t>::required_alignment) two_pointers_t two_pointers;

static_assert(std::atomic_ref<two_pointers_t>::required_alignment == sizeof(two_pointers_t));

#ifdef _WIN64
static_assert(std::atomic_ref<two_pointers_t>::is_always_lock_free == _STD_ATOMIC_ALWAYS_USE_CMPXCHG16B);
#else
static_assert(std::atomic_ref<two_pointers_t>::is_always_lock_free);
#endif

// we expect tests to run on DCAS machine. Win8+ require that
assert(std::atomic_ref<two_pointers_t>(two_pointers).is_lock_free());
}

int main() {
test_ops<false, char>();
test_ops<false, signed char>();
Expand Down Expand Up @@ -425,4 +445,5 @@ int main() {
test_ptr_ops<long*>();

test_gh_1497();
test_gh_4472();
}
6 changes: 3 additions & 3 deletions tests/std/tests/usual_20_matrix.lst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ PM_CL="/clr /MD /std:c++20"
PM_CL="/clr /MDd /std:c++20"
PM_CL="/BE /c /EHsc /MD /std:c++20 /permissive-"
PM_CL="/BE /c /EHsc /MTd /std:c++latest /permissive-"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++20 /permissive- /MD --start-no-unused-arguments"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++latest /permissive- /MTd /fp:strict --start-no-unused-arguments"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++latest /permissive- /MT /fp:strict -fsanitize=undefined -fno-sanitize-recover=undefined --start-no-unused-arguments"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++20 /permissive- /MD --start-no-unused-arguments -mcx16"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++latest /permissive- /MTd /fp:strict --start-no-unused-arguments -mcx16"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /EHsc /std:c++latest /permissive- /MT /fp:strict -fsanitize=undefined -fno-sanitize-recover=undefined --start-no-unused-arguments -mcx16"
1 change: 1 addition & 0 deletions tests/utils/stl/test/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def getDefaultFeatures(config, litConfig):
DEFAULT_FEATURES.append(Feature(name='edg'))
DEFAULT_FEATURES.append(Feature(name='arch_avx2'))
DEFAULT_FEATURES.append(Feature(name='x64'))
DEFAULT_FEATURES.append(Feature(name='cx16'))

elif litConfig.target_arch.casefold() == 'arm'.casefold():
DEFAULT_FEATURES.append(Feature(name='arch_vfpv4'))
Expand Down
2 changes: 2 additions & 0 deletions tests/utils/stl/test/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ def _parseFlags(self, litConfig):
foundCRT = True
elif flag[1:] == 'analyze:plugin':
afterAnalyzePlugin = True
elif flag[1:] == 'D_STD_ATOMIC_ALWAYS_USE_CMPXCHG16B=1':
self.requires.append('cx16')

if not foundStd:
self._addCustomFeature('c++14')
Expand Down
Loading