From 6cfdbde15a2ce3148f596021882f586895c0a4be Mon Sep 17 00:00:00 2001 From: "S. B. Tam" Date: Wed, 3 Sep 2025 19:32:13 +0800 Subject: [PATCH 1/2] Workaround non-atomic `__iso_volatile_{load,store}64` on x86 clang-cl --- stl/inc/atomic | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/stl/inc/atomic b/stl/inc/atomic index 6758d4ea83..9f4613dae5 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1000,7 +1000,12 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics void store(const _TVal _Value) noexcept { // store with sequential consistency const auto _Mem = _STD _Atomic_address_as(_Storage); const long long _As_bytes = _STD _Atomic_reinterpret_as(_Value); +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 + static_assert(_M_IX86_FP != 0, "8 byte atomic store is not supported on clang-cl with /arch:IA32"); + __atomic_store_n(_Mem, _As_bytes, __ATOMIC_SEQ_CST); +#else // ^^^ workaround / no workaround vvv _ATOMIC_STORE_64_SEQ_CST(_Mem, _As_bytes); +#endif // ^^^ no workaround ^^^ } void store(const _TVal _Value, const memory_order _Order) noexcept { // store with given memory order @@ -1010,9 +1015,17 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics _Check_store_memory_order(_Order); if (_Order == memory_order_relaxed) { +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 + __atomic_store_n(_Mem, _As_bytes, __ATOMIC_RELAXED); +#else // ^^^ workaround / no workaround vvv __iso_volatile_store64(_Mem, _As_bytes); +#endif // ^^^ no workaround ^^^ } else if (_Order == memory_order_release) { +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 + __atomic_store_n(_Mem, _As_bytes, __ATOMIC_RELEASE); +#else // ^^^ workaround / no workaround vvv __STORE_RELEASE(64, _Mem, _As_bytes); +#endif // ^^^ no workaround ^^^ } else { store(_Value); } @@ -1025,7 +1038,12 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 _ATOMIC_LOAD_ARM64(_As_bytes, 64, _Mem, _Order) #else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR != 1 vvv +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 + static_assert(_M_IX86_FP != 0, "8 byte atomic load is not supported on clang-cl with /arch:IA32"); + _As_bytes = __atomic_load_n(_Mem, __ATOMIC_RELAXED); +#else // ^^^ workaround / no workaround vvv _As_bytes = __iso_volatile_load64(_Mem); +#endif // ^^^ no workaround ^^^ _ATOMIC_POST_LOAD_BARRIER_AS_NEEDED(_Order) #endif // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR != 1 ^^^ return reinterpret_cast<_TVal&>(_As_bytes); From 7e010269de1caebc5ca6c91a6c86ae8a1fd35de5 Mon Sep 17 00:00:00 2001 From: "S. B. Tam" Date: Wed, 3 Sep 2025 20:24:24 +0800 Subject: [PATCH 2/2] Point to LLVM-126516 instead --- stl/inc/atomic | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/atomic b/stl/inc/atomic index 9f4613dae5..e337f6b24a 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -1000,7 +1000,7 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics void store(const _TVal _Value) noexcept { // store with sequential consistency const auto _Mem = _STD _Atomic_address_as(_Storage); const long long _As_bytes = _STD _Atomic_reinterpret_as(_Value); -#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-126516 static_assert(_M_IX86_FP != 0, "8 byte atomic store is not supported on clang-cl with /arch:IA32"); __atomic_store_n(_Mem, _As_bytes, __ATOMIC_SEQ_CST); #else // ^^^ workaround / no workaround vvv @@ -1015,13 +1015,13 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics _Check_store_memory_order(_Order); if (_Order == memory_order_relaxed) { -#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-126516 __atomic_store_n(_Mem, _As_bytes, __ATOMIC_RELAXED); #else // ^^^ workaround / no workaround vvv __iso_volatile_store64(_Mem, _As_bytes); #endif // ^^^ no workaround ^^^ } else if (_Order == memory_order_release) { -#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-126516 __atomic_store_n(_Mem, _As_bytes, __ATOMIC_RELEASE); #else // ^^^ workaround / no workaround vvv __STORE_RELEASE(64, _Mem, _As_bytes); @@ -1038,7 +1038,7 @@ struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics #if _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 _ATOMIC_LOAD_ARM64(_As_bytes, 64, _Mem, _Order) #else // ^^^ _STD_ATOMIC_USE_ARM64_LDAR_STLR == 1 / _STD_ATOMIC_USE_ARM64_LDAR_STLR != 1 vvv -#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-156228 +#if defined(__clang__) && defined(_M_IX86) // TRANSITION, LLVM-126516 static_assert(_M_IX86_FP != 0, "8 byte atomic load is not supported on clang-cl with /arch:IA32"); _As_bytes = __atomic_load_n(_Mem, __ATOMIC_RELAXED); #else // ^^^ workaround / no workaround vvv