[libcxx-commits] [libcxx] [libc++][In progress] Floating Point Atomic (PR #67799)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Oct 15 06:01:22 PDT 2023


https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/67799

>From 60b5b03d87c3dc27ef907421645a67b842599b48 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 28 Jun 2023 15:47:39 +0100
Subject: [PATCH 01/18] [libc++][In progress] Floating Point Atomic

- implement P0020R6 Floating Point Atomic

Differential Revision: https://reviews.llvm.org/D153981
---
 libcxx/include/__atomic/atomic.h              | 118 ++++++++++++++++++
 .../atomics.types.float/copy.compile.pass.cpp |  29 +++++
 .../atomics.types.float/ctor.pass.cpp         |  39 ++++++
 .../atomics.types.float/fetch_add.pass.cpp    |  81 ++++++++++++
 .../atomics.types.float/fetch_sub.pass.cpp    |  50 ++++++++
 .../atomics.types.float/lockfree.pass.cpp     |  52 ++++++++
 .../typedef.compile.pass.cpp                  |  25 ++++
 7 files changed, 394 insertions(+)
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/copy.compile.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/typedef.compile.pass.cpp

diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index 47de6b958a96c1b..7b17c1cbbd98640 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -14,11 +14,15 @@
 #include <__atomic/cxx_atomic_impl.h>
 #include <__atomic/memory_order.h>
 #include <__config>
+#include <__functional/operations.h>
 #include <__memory/addressof.h>
+#include <__type_traits/is_floating_point.h>
 #include <__type_traits/is_function.h>
 #include <__type_traits/is_same.h>
 #include <__type_traits/remove_pointer.h>
+#include <__utility/forward.h>
 #include <cstddef>
+#include <cstdio>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -136,6 +140,120 @@ struct atomic<_Tp*>
     atomic& operator=(const atomic&) volatile = delete;
 };
 
+#if _LIBCPP_STD_VER >= 20
+template <class _Tp> requires is_floating_point_v<_Tp>
+struct atomic<_Tp>
+    : public __atomic_base<_Tp>
+{
+  private:
+    // see lib/Sema/SemaChecking.cpp approx. line 6748, function IsAllowedValueType
+    // // LLVM Parser does not allow atomicrmw with x86_fp80 type.
+    //if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+    //    &Context.getTargetInfo().getLongDoubleFormat() ==
+    //        &llvm::APFloat::x87DoubleExtended())
+
+    // this is platform dependent. How can we get the correct answer?
+    _LIBCPP_HIDE_FROM_ABI static constexpr bool __has_rmw_builtin = !std::is_same_v<_Tp, long double>;
+
+    template <class _This, class _BuiltinOp, class _Operation>
+    _LIBCPP_HIDE_FROM_ABI static _Tp __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _BuiltinOp __builtin_op, _Operation __operation) {
+        if constexpr (__has_rmw_builtin) {
+            return __builtin_op(std::addressof(std::forward<_This>(__self).__a_), __operand, __m);
+        } else {
+            _Tp __old = __self.load(memory_order_relaxed);
+            _Tp __new = __operation(__old, __operand);
+            while(!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
+                if constexpr (std::is_same_v<_Tp, long double>){
+                    // https://reviews.llvm.org/D53965
+                    // https://bugs.llvm.org/show_bug.cgi?id=48634
+                    // clang bug: __old is not updated on failure for atomic<long double>
+                    __old = __self.load(memory_order_relaxed);
+                }
+                __new = __operation(__old, __operand);
+            }
+            return __old;
+        }
+    }
+
+    template <class _This>
+    _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_add(_This&& __self, _Tp __operand, memory_order __m) {
+        auto __builtin_op = [](auto __a, auto __operand, auto __order){
+            return std::__cxx_atomic_fetch_add(__a, __operand, __order);
+        };
+        return __rmw_op(std::forward<_This>(__self), __operand, __m, __builtin_op, std::plus<>{});
+    }
+
+    template <class _This>
+    _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_sub(_This&& __self, _Tp __operand, memory_order __m) {
+        auto __builtin_op = [](auto __a, auto __operand, auto __order){
+            return std::__cxx_atomic_fetch_sub(__a, __operand, __order);
+        };
+        return __rmw_op(std::forward<_This>(__self), __operand, __m, __builtin_op, std::minus<>{});
+    }
+
+  public:
+    using __base          = __atomic_base<_Tp>;
+    using value_type      = _Tp;
+    using difference_type = value_type;
+
+    _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default;
+    _LIBCPP_HIDE_FROM_ABI constexpr atomic(_Tp __d) noexcept : __base(__d) {}
+
+    atomic(const atomic&) = delete;
+    atomic& operator=(const atomic&) = delete;
+    atomic& operator=(const atomic&) volatile = delete;
+
+    _LIBCPP_HIDE_FROM_ABI
+    _Tp operator=(_Tp __d) volatile noexcept
+        {__base::store(__d); return __d;}
+    _LIBCPP_HIDE_FROM_ABI
+    _Tp operator=(_Tp __d) noexcept
+        {__base::store(__d); return __d;}
+
+    _LIBCPP_HIDE_FROM_ABI
+    _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
+      requires __base::is_always_lock_free {
+        return __fetch_add(*this, __op, __m);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
+        return __fetch_add(*this, __op, __m);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
+      requires __base::is_always_lock_free {
+        return __fetch_sub(*this, __op, __m);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
+        return __fetch_sub(*this, __op, __m);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile noexcept
+      requires __base::is_always_lock_free {
+        return fetch_add(__op) + __op;
+    }
+
+    _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) noexcept {
+        return fetch_add(__op) + __op;
+    }
+
+    _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile noexcept
+      requires __base::is_always_lock_free {
+        return fetch_sub(__op) - __op;
+    }
+
+    _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) noexcept {
+        return fetch_sub(__op) - __op;
+    }
+
+};
+
+#endif // _LIBCPP_STD_VER >= 20
+
 // atomic_is_lock_free
 
 template <class _Tp>
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/copy.compile.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/copy.compile.pass.cpp
new file mode 100644
index 000000000000000..3984d621ad3ab04
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/copy.compile.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//  atomic(const atomic&) = delete;
+//  atomic& operator=(const atomic&) = delete;
+//  atomic& operator=(const atomic&) volatile = delete;
+
+#include <atomic>
+#include <type_traits>
+
+template <class T>
+void test() {
+  static_assert(!std::is_copy_assignable_v<std::atomic<T>>);
+  static_assert(!std::is_copy_constructible_v<std::atomic<T>>);
+  static_assert(!std::is_move_constructible_v<std::atomic<T>>);
+  static_assert(!std::is_move_assignable_v<std::atomic<T>>);
+  static_assert(!std::is_assignable_v<volatile std::atomic<T>&, const std::atomic<T>&>);
+}
+
+template void test<float>();
+template void test<double>();
+template void test<long double>();
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
new file mode 100644
index 000000000000000..8fc6ac0f34cf1ed
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// constexpr atomic() noexcept;
+// constexpr atomic(floating-point-type) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+
+template <class T>
+void test() {
+  // constexpr atomic() noexcept;
+  {
+    constexpr std::atomic<T> a = {};
+    assert(a.load() == T(0));
+  }
+
+  // constexpr atomic(floating-point-type) noexcept;
+  {
+    constexpr std::atomic<T> a = T(5.2);
+    assert(a.load() == T(5.2));
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
new file mode 100644
index 000000000000000..32f5f4097165ae4
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <vector>
+
+#include "test_macros.h"
+#include "make_test_thread.h"
+
+template <class T>
+void test() {
+  // fetch_add
+  {
+    std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(1.2);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+
+  // fetch_add volatile
+  {
+    volatile std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(1.2);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+
+  // fetch_add concurrent
+  {
+    constexpr auto numberOfThreads = 4;
+    constexpr auto loop            = 1000;
+
+    std::atomic<T> at;
+
+    std::vector<std::thread> threads;
+    threads.reserve(numberOfThreads);
+    for (auto i = 0; i < numberOfThreads; ++i) {
+      threads.emplace_back([&at]() {
+        for (auto j = 0; j < loop; ++j) {
+          at.fetch_add(T(1.234));
+        }
+      });
+    }
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+
+    const auto times = [](T t, int n) {
+      T res(0);
+      for (auto i = 0; i < n; ++i) {
+        res += t;
+      }
+      return res;
+    };
+
+    assert(at.load() == times(1.234, numberOfThreads * loop));
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
new file mode 100644
index 000000000000000..ce3aa57e506acfd
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+// floating-point-type fetch_sub(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_sub(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+
+template <class T>
+void test() {
+  // fetch_add
+  {
+    std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(1.2);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+
+  // fetch_sub
+  {
+    std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_sub(1.2);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) - T(1.2));
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
new file mode 100644
index 000000000000000..b632df79c330486
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//   static constexpr bool is_always_lock_free = implementation-defined;
+//   bool is_lock_free() const volatile noexcept;
+//   bool is_lock_free() const noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+
+template <class T>
+concept isLockFreeNoexcept = requires(T t) {
+  { t.is_lock_free() } noexcept;
+};
+
+template <class T>
+void test() {
+  static_assert(isLockFreeNoexcept<const std::atomic<T>>);
+  static_assert(isLockFreeNoexcept<const volatile std::atomic<T>>);
+
+  //   static constexpr bool is_always_lock_free = implementation-defined;
+  { [[maybe_unused]] constexpr std::same_as<const bool> decltype(auto) r = std::atomic<T>::is_always_lock_free; }
+
+  //   bool is_lock_free() const volatile noexcept;
+  {
+    const volatile std::atomic<T> a;
+    [[maybe_unused]] std::same_as<bool> decltype(auto) r = a.is_lock_free();
+  }
+
+  //   bool is_lock_free() const noexcept;
+  {
+    const std::atomic<T> a;
+    [[maybe_unused]] std::same_as<bool> decltype(auto) r = a.is_lock_free();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/typedef.compile.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/typedef.compile.pass.cpp
new file mode 100644
index 000000000000000..1046665f1c8fa26
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/typedef.compile.pass.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//    using value_type = floating-point-type;
+//    using difference_type = value_type;
+
+#include <atomic>
+#include <type_traits>
+
+template <class T>
+void test() {
+  static_assert(std::is_same_v<typename std::atomic<T>::value_type, T>);
+  static_assert(std::is_same_v<typename std::atomic<T>::difference_type, T>);
+}
+
+template void test<float>();
+template void test<double>();
+template void test<long double>();

>From 8dfd92d952aa047a5ae539766c3e045f46dd1e26 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Mon, 2 Oct 2023 16:16:02 +0100
Subject: [PATCH 02/18] more tests

---
 libcxx/include/__atomic/atomic.h              | 56 ++++++------
 .../atomics.types.float/fetch_add.pass.cpp    | 22 +++--
 .../atomics.types.float/fetch_sub.pass.cpp    | 59 ++++++++++---
 .../operator.minus_equals.pass.cpp            | 85 +++++++++++++++++++
 .../operator.plus_equals.pass.cpp             | 85 +++++++++++++++++++
 ...ompile.pass.cpp => types.compile.pass.cpp} |  3 +
 6 files changed, 260 insertions(+), 50 deletions(-)
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
 rename libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/{typedef.compile.pass.cpp => types.compile.pass.cpp} (77%)

diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index 7b17c1cbbd98640..36cfc1c9bbd0a39 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -146,49 +146,43 @@ struct atomic<_Tp>
     : public __atomic_base<_Tp>
 {
   private:
-    // see lib/Sema/SemaChecking.cpp approx. line 6748, function IsAllowedValueType
-    // // LLVM Parser does not allow atomicrmw with x86_fp80 type.
-    //if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+    // The builtin __cxx_atomic_fetch_add does not work for
+    // long double on some platforms with fp80 type
+    // There is no way on the libc++ side to test whether it is
+    // ok to use the builtin for a certain type.
+    // Therefore, we do not use the builtin here
+    // For more details, see 
+    // lib/Sema/SemaChecking.cpp function IsAllowedValueType
+    // LLVM Parser does not allow atomicrmw with x86_fp80 type.
+    // if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) &&
     //    &Context.getTargetInfo().getLongDoubleFormat() ==
     //        &llvm::APFloat::x87DoubleExtended())
-
-    // this is platform dependent. How can we get the correct answer?
-    _LIBCPP_HIDE_FROM_ABI static constexpr bool __has_rmw_builtin = !std::is_same_v<_Tp, long double>;
-
-    template <class _This, class _BuiltinOp, class _Operation>
-    _LIBCPP_HIDE_FROM_ABI static _Tp __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _BuiltinOp __builtin_op, _Operation __operation) {
-        if constexpr (__has_rmw_builtin) {
-            return __builtin_op(std::addressof(std::forward<_This>(__self).__a_), __operand, __m);
-        } else {
-            _Tp __old = __self.load(memory_order_relaxed);
-            _Tp __new = __operation(__old, __operand);
-            while(!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
-                if constexpr (std::is_same_v<_Tp, long double>){
-                    // https://reviews.llvm.org/D53965
-                    // https://bugs.llvm.org/show_bug.cgi?id=48634
-                    // clang bug: __old is not updated on failure for atomic<long double>
-                    __old = __self.load(memory_order_relaxed);
-                }
-                __new = __operation(__old, __operand);
+    // For more info
+    // https://reviews.llvm.org/D53965
+
+    template <class _This, class _Operation>
+    _LIBCPP_HIDE_FROM_ABI static _Tp __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _Operation __operation) {
+        _Tp __old = __self.load(memory_order_relaxed);
+        _Tp __new = __operation(__old, __operand);
+        while(!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
+            if constexpr (std::is_same_v<_Tp, long double>){
+                // https://bugs.llvm.org/show_bug.cgi?id=48634
+                // clang bug: __old is not updated on failure for atomic<long double>
+                __old = __self.load(memory_order_relaxed);
             }
-            return __old;
+            __new = __operation(__old, __operand);
         }
+        return __old;
     }
 
     template <class _This>
     _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_add(_This&& __self, _Tp __operand, memory_order __m) {
-        auto __builtin_op = [](auto __a, auto __operand, auto __order){
-            return std::__cxx_atomic_fetch_add(__a, __operand, __order);
-        };
-        return __rmw_op(std::forward<_This>(__self), __operand, __m, __builtin_op, std::plus<>{});
+        return __rmw_op(std::forward<_This>(__self), __operand, __m, std::plus<>{});
     }
 
     template <class _This>
     _LIBCPP_HIDE_FROM_ABI static _Tp __fetch_sub(_This&& __self, _Tp __operand, memory_order __m) {
-        auto __builtin_op = [](auto __a, auto __operand, auto __order){
-            return std::__cxx_atomic_fetch_sub(__a, __operand, __order);
-        };
-        return __rmw_op(std::forward<_This>(__self), __operand, __m, __builtin_op, std::minus<>{});
+        return __rmw_op(std::forward<_This>(__self), __operand, __m, std::minus<>{});
     }
 
   public:
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 32f5f4097165ae4..a156364af93e373 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -21,34 +21,40 @@
 #include "test_macros.h"
 #include "make_test_thread.h"
 
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T> a, T t) { a.fetch_add(t); };
+
 template <class T>
 void test() {
+  static_assert(noexcept(std::declval<std::atomic<T>&>().fetch_add(T(0))));
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+
   // fetch_add
   {
     std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_add(1.2);
+    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2));
     assert(r == T(3.1));
     assert(a.load() == T(3.1) + T(1.2));
   }
 
   // fetch_add volatile
-  {
+  if constexpr (std::atomic<T>::is_always_lock_free) {
     volatile std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_add(1.2);
+    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2));
     assert(r == T(3.1));
     assert(a.load() == T(3.1) + T(1.2));
   }
 
   // fetch_add concurrent
   {
-    constexpr auto numberOfThreads = 4;
-    constexpr auto loop            = 1000;
+    constexpr auto number_of_threads = 4;
+    constexpr auto loop              = 1000;
 
     std::atomic<T> at;
 
     std::vector<std::thread> threads;
-    threads.reserve(numberOfThreads);
-    for (auto i = 0; i < numberOfThreads; ++i) {
+    threads.reserve(number_of_threads);
+    for (auto i = 0; i < number_of_threads; ++i) {
       threads.emplace_back([&at]() {
         for (auto j = 0; j < loop; ++j) {
           at.fetch_add(T(1.234));
@@ -68,7 +74,7 @@ void test() {
       return res;
     };
 
-    assert(at.load() == times(1.234, numberOfThreads * loop));
+    assert(at.load() == times(1.234, number_of_threads * loop));
   }
 }
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index ce3aa57e506acfd..b37383d0dec5294 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -7,10 +7,6 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 
-// floating-point-type fetch_add(floating-point-type,
-//                               memory_order = memory_order::seq_cst) volatile noexcept;
-// floating-point-type fetch_add(floating-point-type,
-//                               memory_order = memory_order::seq_cst) noexcept;
 // floating-point-type fetch_sub(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
 // floating-point-type fetch_sub(floating-point-type,
@@ -19,26 +15,67 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <thread>
+#include <vector>
 
 #include "test_macros.h"
+#include "make_test_thread.h"
+
+template <class T>
+concept HasVolatileFetchSub = requires(volatile std::atomic<T> a, T t) { a.fetch_sub(t); };
 
 template <class T>
 void test() {
-  // fetch_add
+  static_assert(noexcept(std::declval<std::atomic<T>&>().fetch_sub(T(0))));
+  static_assert(HasVolatileFetchSub<T> == std::atomic<T>::is_always_lock_free);
+
+  // fetch_sub
   {
     std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_add(1.2);
+    std::same_as<T> decltype(auto) r = a.fetch_sub(T(1.2));
     assert(r == T(3.1));
-    assert(a.load() == T(3.1) + T(1.2));
+    assert(a.load() == T(3.1) - T(1.2));
   }
 
-  // fetch_sub
-  {
-    std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_sub(1.2);
+  // fetch_sub volatile
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    volatile std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_sub(T(1.2));
     assert(r == T(3.1));
     assert(a.load() == T(3.1) - T(1.2));
   }
+
+  // fetch_sub concurrent
+  {
+    constexpr auto number_of_threads = 4;
+    constexpr auto loop              = 1000;
+
+    std::atomic<T> at;
+
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+    for (auto i = 0; i < number_of_threads; ++i) {
+      threads.emplace_back([&at]() {
+        for (auto j = 0; j < loop; ++j) {
+          at.fetch_sub(T(1.234));
+        }
+      });
+    }
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+
+    const auto accu_neg = [](T t, int n) {
+      T res(0);
+      for (auto i = 0; i < n; ++i) {
+        res -= t;
+      }
+      return res;
+    };
+
+    assert(at.load() == accu_neg(1.234, number_of_threads * loop));
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
new file mode 100644
index 000000000000000..5a04e9e94027d4a
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// floating-point-type operator-=(floating-point-type) volatile noexcept;
+// floating-point-type operator-=(floating-point-type) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <vector>
+
+#include "test_macros.h"
+#include "make_test_thread.h"
+
+template <class T>
+concept HasVolatileMinusEquals = requires(volatile std::atomic<T> a, T t) { a -= t; };
+
+template <class T>
+void test() {
+  static_assert(noexcept(std::declval<std::atomic<T>&>() -= T(0)));
+  static_assert(HasVolatileMinusEquals<T> == std::atomic<T>::is_always_lock_free);
+
+  // -=
+  {
+    std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a -= T(1.2);
+    assert(r == T(3.1) - T(1.2));
+    assert(a.load() == T(3.1) - T(1.2));
+  }
+
+  // -= volatile
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    volatile std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a -= T(1.2);
+    assert(r == T(3.1) - T(1.2));
+    assert(a.load() == T(3.1) - T(1.2));
+  }
+
+  // -= concurrent
+  {
+    constexpr auto number_of_threads = 4;
+    constexpr auto loop              = 1000;
+
+    std::atomic<T> at;
+
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+    for (auto i = 0; i < number_of_threads; ++i) {
+      threads.emplace_back([&at]() {
+        for (auto j = 0; j < loop; ++j) {
+          at -= T(1.234);
+        }
+      });
+    }
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+
+    const auto accu_neg = [](T t, int n) {
+      T res(0);
+      for (auto i = 0; i < n; ++i) {
+        res -= t;
+      }
+      return res;
+    };
+
+    assert(at.load() == accu_neg(1.234, number_of_threads * loop));
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
new file mode 100644
index 000000000000000..9cace80331736b8
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// floating-point-type operator+=(floating-point-type) volatile noexcept;
+// floating-point-type operator+=(floating-point-type) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <vector>
+
+#include "test_macros.h"
+#include "make_test_thread.h"
+
+template <class T>
+concept HasVolatilePlusEquals = requires(volatile std::atomic<T> a, T t) { a += t; };
+
+template <class T>
+void test() {
+  static_assert(noexcept(std::declval<std::atomic<T>&>() += T(0)));
+  static_assert(HasVolatilePlusEquals<T> == std::atomic<T>::is_always_lock_free);
+
+  // +=
+  {
+    std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a += T(1.2);
+    assert(r == T(3.1) + T(1.2));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+
+  // += volatile
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    volatile std::atomic<T> a(3.1);
+    std::same_as<T> decltype(auto) r = a += T(1.2);
+    assert(r == T(3.1) + T(1.2));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+
+  // += concurrent
+  {
+    constexpr auto number_of_threads = 4;
+    constexpr auto loop              = 1000;
+
+    std::atomic<T> at;
+
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+    for (auto i = 0; i < number_of_threads; ++i) {
+      threads.emplace_back([&at]() {
+        for (auto j = 0; j < loop; ++j) {
+          at += T(1.234);
+        }
+      });
+    }
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+
+    const auto times = [](T t, int n) {
+      T res(0);
+      for (auto i = 0; i < n; ++i) {
+        res += t;
+      }
+      return res;
+    };
+
+    assert(at.load() == times(1.234, number_of_threads * loop));
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/typedef.compile.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/types.compile.pass.cpp
similarity index 77%
rename from libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/typedef.compile.pass.cpp
rename to libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/types.compile.pass.cpp
index 1046665f1c8fa26..1a4e6dfe0b31553 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/typedef.compile.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/types.compile.pass.cpp
@@ -10,6 +10,7 @@
 
 //    using value_type = floating-point-type;
 //    using difference_type = value_type;
+// The atomic floating-point specializations are standard-layout structs. They each have a trivial destructor.
 
 #include <atomic>
 #include <type_traits>
@@ -18,6 +19,8 @@ template <class T>
 void test() {
   static_assert(std::is_same_v<typename std::atomic<T>::value_type, T>);
   static_assert(std::is_same_v<typename std::atomic<T>::difference_type, T>);
+  static_assert(std::is_standard_layout_v<std::atomic<T>>);
+  static_assert(std::is_trivially_destructible_v<std::atomic<T>>);
 }
 
 template void test<float>();

>From 6bc9f111965add38d2fcd1902c040e5684619542 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Mon, 9 Oct 2023 17:48:21 +0100
Subject: [PATCH 03/18] address feedback and rebase

---
 libcxx/docs/ReleaseNotes/18.rst               |  1 +
 libcxx/docs/Status/Cxx20Papers.csv            |  2 +-
 libcxx/include/__atomic/atomic.h              | 75 +++++++++----------
 libcxx/include/atomic                         | 66 ++++++++++++++++
 .../atomics.types.float/locakfree.pass.cpp    | 49 ++++++++++++
 .../atomics.types.float/ctor.pass.cpp         | 42 +++++++++--
 .../atomics.types.float/fetch_add.pass.cpp    |  1 +
 .../atomics.types.float/fetch_sub.pass.cpp    |  1 +
 8 files changed, 189 insertions(+), 48 deletions(-)
 create mode 100644 libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/locakfree.pass.cpp

diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index ac78563aa73848f..79392bb18cf2490 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -47,6 +47,7 @@ Implemented Papers
 - P2443R1 - ``views::chunk_by``
 - P2538R1 - ADL-proof ``std::projected``
 - P2614R2 - Deprecate ``numeric_limits::has_denorm``
+- P0020R6 - Floating Point Atomic
 
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index dd6fcf9a7583ce3..3b28cfa49e18a28 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -2,7 +2,7 @@
 "`P0463R1 <https://wg21.link/P0463R1>`__","LWG","Endian just Endian","Toronto","|Complete|","7.0"
 "`P0674R1 <https://wg21.link/P0674R1>`__","LWG","Extending make_shared to Support Arrays","Toronto","|Complete|","15.0"
 "","","","","","",""
-"`P0020R6 <https://wg21.link/P0020R6>`__","LWG","Floating Point Atomic","Albuquerque","",""
+"`P0020R6 <https://wg21.link/P0020R6>`__","LWG","Floating Point Atomic","Albuquerque","|Complete|","18.0"
 "`P0053R7 <https://wg21.link/P0053R7>`__","LWG","C++ Synchronized Buffered Ostream","Albuquerque","",""
 "`P0202R3 <https://wg21.link/P0202R3>`__","LWG","Add constexpr modifiers to functions in <algorithm> and <utility> Headers","Albuquerque","|Complete|","12.0"
 "`P0415R1 <https://wg21.link/P0415R1>`__","LWG","Constexpr for ``std::complex``\ ","Albuquerque","|Complete|","16.0"
diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index 36cfc1c9bbd0a39..c4159dcfb6ffdb2 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -141,36 +141,36 @@ struct atomic<_Tp*>
 };
 
 #if _LIBCPP_STD_VER >= 20
-template <class _Tp> requires is_floating_point_v<_Tp>
-struct atomic<_Tp>
-    : public __atomic_base<_Tp>
-{
+template <class _Tp>
+  requires is_floating_point_v<_Tp>
+struct atomic<_Tp> : public __atomic_base<_Tp> {
   private:
     // The builtin __cxx_atomic_fetch_add does not work for
     // long double on some platforms with fp80 type
     // There is no way on the libc++ side to test whether it is
     // ok to use the builtin for a certain type.
     // Therefore, we do not use the builtin here
-    // For more details, see 
+    // For more details, see
     // lib/Sema/SemaChecking.cpp function IsAllowedValueType
     // LLVM Parser does not allow atomicrmw with x86_fp80 type.
     // if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) &&
     //    &Context.getTargetInfo().getLongDoubleFormat() ==
     //        &llvm::APFloat::x87DoubleExtended())
     // For more info
+    // https://github.com/llvm/llvm-project/issues/68602
     // https://reviews.llvm.org/D53965
 
     template <class _This, class _Operation>
     _LIBCPP_HIDE_FROM_ABI static _Tp __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _Operation __operation) {
         _Tp __old = __self.load(memory_order_relaxed);
         _Tp __new = __operation(__old, __operand);
-        while(!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
-            if constexpr (std::is_same_v<_Tp, long double>){
-                // https://bugs.llvm.org/show_bug.cgi?id=48634
-                // clang bug: __old is not updated on failure for atomic<long double>
-                __old = __self.load(memory_order_relaxed);
-            }
-            __new = __operation(__old, __operand);
+        while (!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
+          if constexpr (std::is_same_v<_Tp, long double>) {
+            // https://github.com/llvm/llvm-project/issues/47978
+            // clang bug: __old is not updated on failure for atomic<long double>
+            __old = __self.load(memory_order_relaxed);
+          }
+          __new = __operation(__old, __operand);
         }
         return __old;
     }
@@ -193,57 +193,54 @@ struct atomic<_Tp>
     _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default;
     _LIBCPP_HIDE_FROM_ABI constexpr atomic(_Tp __d) noexcept : __base(__d) {}
 
-    atomic(const atomic&) = delete;
-    atomic& operator=(const atomic&) = delete;
+    atomic(const atomic&)                     = delete;
+    atomic& operator=(const atomic&)          = delete;
     atomic& operator=(const atomic&) volatile = delete;
 
-    _LIBCPP_HIDE_FROM_ABI
-    _Tp operator=(_Tp __d) volatile noexcept
-        {__base::store(__d); return __d;}
-    _LIBCPP_HIDE_FROM_ABI
-    _Tp operator=(_Tp __d) noexcept
-        {__base::store(__d); return __d;}
+    _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept {
+        __base::store(__d);
+        return __d;
+    }
+    _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) noexcept {
+        __base::store(__d);
+        return __d;
+    }
 
-    _LIBCPP_HIDE_FROM_ABI
-    _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
-      requires __base::is_always_lock_free {
+    _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
+      requires __base::is_always_lock_free
+    {
         return __fetch_add(*this, __op, __m);
     }
 
-    _LIBCPP_HIDE_FROM_ABI
-    _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
+    _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
         return __fetch_add(*this, __op, __m);
     }
 
-    _LIBCPP_HIDE_FROM_ABI
-    _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
-      requires __base::is_always_lock_free {
+    _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) volatile noexcept
+      requires __base::is_always_lock_free
+    {
         return __fetch_sub(*this, __op, __m);
     }
 
-    _LIBCPP_HIDE_FROM_ABI
-    _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
+    _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __op, memory_order __m = memory_order_seq_cst) noexcept {
         return __fetch_sub(*this, __op, __m);
     }
 
     _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) volatile noexcept
-      requires __base::is_always_lock_free {
+      requires __base::is_always_lock_free
+    {
         return fetch_add(__op) + __op;
     }
 
-    _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) noexcept {
-        return fetch_add(__op) + __op;
-    }
+    _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __op) noexcept { return fetch_add(__op) + __op; }
 
     _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) volatile noexcept
-      requires __base::is_always_lock_free {
-        return fetch_sub(__op) - __op;
-    }
-
-    _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) noexcept {
+      requires __base::is_always_lock_free
+    {
         return fetch_sub(__op) - __op;
     }
 
+    _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) noexcept { return fetch_sub(__op) - __op; }
 };
 
 #endif // _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/atomic b/libcxx/include/atomic
index 2f122a707bdc33a..c52bf7521635f02 100644
--- a/libcxx/include/atomic
+++ b/libcxx/include/atomic
@@ -262,6 +262,72 @@ struct atomic<T*>
     void notify_all() noexcept;
 };
 
+template<> 
+struct atomic<floating-point-type> {
+  using value_type = floating-point-type;
+  using difference_type = value_type;
+
+  static constexpr bool is_always_lock_free = implementation-defined;
+  bool is_lock_free() const volatile noexcept;
+  bool is_lock_free() const noexcept;
+
+  constexpr atomic() noexcept;
+  constexpr atomic(floating-point-type) noexcept;
+  atomic(const atomic&) = delete;
+  atomic& operator=(const atomic&) = delete;
+  atomic& operator=(const atomic&) volatile = delete;
+
+  void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept;
+  void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept;
+  floating-point-type operator=(floating-point-type) volatile noexcept;
+  floating-point-type operator=(floating-point-type) noexcept;
+  floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept;
+  floating-point-type load(memory_order = memory_order::seq_cst) noexcept;
+  operator floating-point-type() volatile noexcept;
+  operator floating-point-type() noexcept;
+
+  floating-point-type exchange(floating-point-type,
+                               memory_order = memory_order::seq_cst) volatile noexcept;
+  floating-point-type exchange(floating-point-type,
+                               memory_order = memory_order::seq_cst) noexcept;
+  bool compare_exchange_weak(floating-point-type&, floating-point-type,
+                             memory_order, memory_order) volatile noexcept;
+  bool compare_exchange_weak(floating-point-type&, floating-point-type,
+                             memory_order, memory_order) noexcept;
+  bool compare_exchange_strong(floating-point-type&, floating-point-type,
+                               memory_order, memory_order) volatile noexcept;
+  bool compare_exchange_strong(floating-point-type&, floating-point-type,
+                               memory_order, memory_order) noexcept;
+  bool compare_exchange_weak(floating-point-type&, floating-point-type,
+                             memory_order = memory_order::seq_cst) volatile noexcept;
+  bool compare_exchange_weak(floating-point-type&, floating-point-type,
+                             memory_order = memory_order::seq_cst) noexcept;
+  bool compare_exchange_strong(floating-point-type&, floating-point-type,
+                               memory_order = memory_order::seq_cst) volatile noexcept;
+  bool compare_exchange_strong(floating-point-type&, floating-point-type,
+                               memory_order = memory_order::seq_cst) noexcept;
+
+  floating-point-type fetch_add(floating-point-type,
+                                memory_order = memory_order::seq_cst) volatile noexcept;
+  floating-point-type fetch_add(floating-point-type,
+                                memory_order = memory_order::seq_cst) noexcept;
+  floating-point-type fetch_sub(floating-point-type,
+                                memory_order = memory_order::seq_cst) volatile noexcept;
+  floating-point-type fetch_sub(floating-point-type,
+                                memory_order = memory_order::seq_cst) noexcept;
+
+  floating-point-type operator+=(floating-point-type) volatile noexcept;
+  floating-point-type operator+=(floating-point-type) noexcept;
+  floating-point-type operator-=(floating-point-type) volatile noexcept;
+  floating-point-type operator-=(floating-point-type) noexcept;
+
+  void wait(floating-point-type, memory_order = memory_order::seq_cst) const volatile noexcept;
+  void wait(floating-point-type, memory_order = memory_order::seq_cst) const noexcept;
+  void notify_one() volatile noexcept;
+  void notify_one() noexcept;
+  void notify_all() volatile noexcept;
+  void notify_all() noexcept;
+};
 
 // [atomics.nonmembers], non-member functions
 template<class T>
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/locakfree.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/locakfree.pass.cpp
new file mode 100644
index 000000000000000..5388ae1c6710fb9
--- /dev/null
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/locakfree.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//   static constexpr bool is_always_lock_free = implementation-defined;
+//   bool is_lock_free() const volatile noexcept;
+//   bool is_lock_free() const noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_macros.h"
+
+template <class T>
+void test() {
+  //   static constexpr bool is_always_lock_free = implementation-defined;
+  {
+    bool r = std::atomic<T>::is_always_lock_free;
+    assert(r == __atomic_always_lock_free(sizeof(T), 0));
+  }
+
+  //   bool is_lock_free() const volatile noexcept;
+  {
+    const volatile std::atomic<T> a;
+    bool r = a.is_lock_free();
+    assert(r == __cxx_atomic_is_lock_free(sizeof(T)));
+  }
+
+  //   bool is_lock_free() const noexcept;
+  {
+    const std::atomic<T> a;
+    bool r = a.is_lock_free();
+    assert(r == __cxx_atomic_is_lock_free(sizeof(T)));
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
index 8fc6ac0f34cf1ed..16df7ff23488759 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
@@ -17,23 +17,49 @@
 #include "test_macros.h"
 
 template <class T>
-void test() {
+constinit std::atomic<T> a1 = T();
+
+template <class T>
+constinit std::atomic<T> a2 = T(5.2);
+
+template <class T>
+constexpr void testOne() {
+  static_assert(std::is_nothrow_constructible_v<std::atomic<T>>);
+  static_assert(std::is_nothrow_constructible_v<std::atomic<T>, T>);
+
   // constexpr atomic() noexcept;
   {
-    constexpr std::atomic<T> a = {};
-    assert(a.load() == T(0));
+    std::atomic<T> a = {};
+    if (!TEST_IS_CONSTANT_EVALUATED) {
+      assert(a.load() == T(0));
+    }
   }
 
   // constexpr atomic(floating-point-type) noexcept;
   {
-    constexpr std::atomic<T> a = T(5.2);
-    assert(a.load() == T(5.2));
+    std::atomic<T> a = T(5.2);
+    if (!TEST_IS_CONSTANT_EVALUATED) {
+      assert(a.load() == T(5.2));
+    }
+  }
+
+  // test constinit
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    assert(a1<T> == T(0.0));
+    assert(a2<T> == T(5.2));
   }
 }
 
+constexpr bool test() {
+  testOne<float>();
+  testOne<double>();
+  testOne<long double>();
+  return true;
+}
+
 int main(int, char**) {
-  test<float>();
-  test<double>();
-  test<long double>();
+  test();
+  static_assert(test());
+
   return 0;
 }
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index a156364af93e373..54780e18e9bec4a 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -5,6 +5,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 
 // floating-point-type fetch_add(floating-point-type,
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index b37383d0dec5294..02a42144a4692e1 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -5,6 +5,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 
 // floating-point-type fetch_sub(floating-point-type,

>From 2b419a113b4525667ae37f2448eab496780990c7 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 11 Oct 2023 20:02:59 +0100
Subject: [PATCH 04/18] more tests

---
 libcxx/include/atomic                         |   2 +-
 .../atomics.types.float/assign.pass.cpp       |  60 ++++
 .../compare_exchange_strong.pass.cpp          | 224 +++++++++++++++
 .../compare_exchange_weak.pass.cpp            | 258 ++++++++++++++++++
 .../atomics.types.float/exchange.pass.cpp     |  72 +++++
 .../atomics.types.float/fetch_add.pass.cpp    |  52 ++--
 .../atomics.types.float/fetch_sub.pass.cpp    |  52 ++--
 .../atomics.types.float/load.pass.cpp         | 129 +++++++++
 .../operator.float.pass.cpp                   |  55 ++++
 .../operator.minus_equals.pass.cpp            |  35 ++-
 .../operator.plus_equals.pass.cpp             |  35 ++-
 .../atomics.types.float/store.pass.cpp        | 104 +++++++
 .../atomics.types.float/test_helper.h         |  96 +++++++
 .../atomics.types.float/wait.pass.cpp         |  80 ++++++
 14 files changed, 1193 insertions(+), 61 deletions(-)
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp

diff --git a/libcxx/include/atomic b/libcxx/include/atomic
index c52bf7521635f02..cafc1585dd453ce 100644
--- a/libcxx/include/atomic
+++ b/libcxx/include/atomic
@@ -262,7 +262,7 @@ struct atomic<T*>
     void notify_all() noexcept;
 };
 
-template<> 
+template<>
 struct atomic<floating-point-type> {
   using value_type = floating-point-type;
   using difference_type = value_type;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
new file mode 100644
index 000000000000000..4f9383c0b934c37
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//  floating-point-type operator=(floating-point-type) volatile noexcept;
+//  floating-point-type operator=(floating-point-type) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileAssign = requires(volatile std::atomic<T> a, T t) { a = t; };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileAssign<T> == std::atomic<T>::is_always_lock_free);
+
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>() = (T(0))));
+
+  // assignment
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = (a = T(1.2));
+    assert(a.load() == T(1.2));
+    assert(r == T(1.2));
+  }
+
+  // memory_order::seq_cst
+  {
+    auto assign = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x = new_val; };
+    auto load   = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(assign, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
new file mode 100644
index 000000000000000..b1f219865d8f95c
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
@@ -0,0 +1,224 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// bool compare_exchange_strong(T& expected, T desired,
+//                            memory_order success, memory_order failure) volatile noexcept;
+// bool compare_exchange_strong(T& expected, T desired,
+//                            memory_order success, memory_order failure) noexcept;
+// bool compare_exchange_strong(T& expected, T desired,
+//                            memory_order order = memory_order::seq_cst) volatile noexcept;
+// bool compare_exchange_strong(T& expected, T desired,
+//                            memory_order order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T, class... Args>
+concept HasVolatileCompareExchangeStrong =
+    requires(volatile std::atomic<T> a, T t, Args... args) { a.compare_exchange_strong(t, t, args...); };
+
+template <class T, template <class> class MaybeVolatile, class... Args>
+concept HasNoexceptCompareExchangeStrong = requires(MaybeVolatile<std::atomic<T>> a, T t, Args... args) {
+  { a.compare_exchange_strong(t, t, args...) } noexcept;
+};
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t, class... MemoryOrder>
+void testBasic(MemoryOrder... memory_order) {
+  static_assert(HasVolatileCompareExchangeStrong<T, MemoryOrder...> == std::atomic<T>::is_always_lock_free);
+  static_assert(HasNoexceptCompareExchangeStrong<T, MaybeVolatile, MemoryOrder...>);
+
+  // compare pass
+  {
+    MaybeVolatile<std::atomic<T>> a(T(1.2));
+    T expected(1.2);
+    const T desired(2.3);
+    std::same_as<bool> decltype(auto) r = a.compare_exchange_strong(expected, desired, memory_order...);
+
+    assert(r);
+    assert(a.load() == desired);
+    assert(expected == T(1.2));
+  }
+
+  // compare fail
+  {
+    MaybeVolatile<std::atomic<T>> a(T(1.2));
+    T expected(1.5);
+    const T desired(2.3);
+    std::same_as<bool> decltype(auto) r = a.compare_exchange_strong(expected, desired, memory_order...);
+
+    assert(!r);
+    assert(a.load() == T(1.2));
+    assert(expected == T(1.2));
+  }
+}
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  testBasic<T, MaybeVolatile>();
+  testBasic<T, MaybeVolatile>(std::memory_order::relaxed);
+  testBasic<T, MaybeVolatile>(std::memory_order::relaxed, std::memory_order_relaxed);
+
+  // test success memory order release
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release, std::memory_order_relaxed);
+      assert(r);
+    };
+
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto store_one_arg = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::release);
+      assert(r);
+    };
+    test_acquire_release<T, MaybeVolatile>(store_one_arg, load);
+  }
+
+  // test success memory order acquire
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_strong(val, val, std::memory_order::acquire, std::memory_order_relaxed)) {
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_strong(val, val, std::memory_order::acquire)) {
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load_one_arg);
+  }
+
+  // test success memory order acq_rel
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel, std::memory_order_relaxed);
+      assert(r);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel, std::memory_order_relaxed)) {
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto store_one_arg = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::acq_rel);
+      assert(r);
+    };
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_strong(val, val, std::memory_order::acq_rel)) {
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store_one_arg, load_one_arg);
+  }
+
+  // test success memory seq_cst
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order_relaxed);
+      assert(r);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order_relaxed)) {
+      }
+      return val;
+    };
+    test_seq_cst<T, MaybeVolatile>(store, load);
+
+    auto store_one_arg = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      auto r = x.compare_exchange_strong(old_val, new_val, std::memory_order::seq_cst, std::memory_order_relaxed);
+      assert(r);
+    };
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_strong(val, val, std::memory_order::seq_cst, std::memory_order_relaxed)) {
+      }
+      return val;
+    };
+    test_seq_cst<T, MaybeVolatile>(store_one_arg, load_one_arg);
+  }
+
+  // test fail memory order acquire
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order_relaxed, std::memory_order_acquire);
+      assert(!r);
+      return result;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order_acquire);
+      assert(!r);
+      return result;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load_one_arg);
+
+    // acq_rel replaced by acquire
+    auto load_one_arg_acq_rel = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order_acq_rel);
+      assert(!r);
+      return result;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load_one_arg_acq_rel);
+  }
+
+  // test fail memory order seq_cst
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_strong(unexpected, unexpected, std::memory_order_relaxed, std::memory_order::seq_cst);
+      assert(!r);
+      return result;
+    };
+    test_seq_cst<T, MaybeVolatile>(store, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  // https://github.com/llvm/llvm-project/issues/47978
+  //test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
new file mode 100644
index 000000000000000..d320fdefc081289
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
@@ -0,0 +1,258 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// bool compare_exchange_weak(T& expected, T desired,
+//                            memory_order success, memory_order failure) volatile noexcept;
+// bool compare_exchange_weak(T& expected, T desired,
+//                            memory_order success, memory_order failure) noexcept;
+// bool compare_exchange_weak(T& expected, T desired,
+//                            memory_order order = memory_order::seq_cst) volatile noexcept;
+// bool compare_exchange_weak(T& expected, T desired,
+//                            memory_order order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T, class... Args>
+concept HasVolatileCompareExchangeWeak =
+    requires(volatile std::atomic<T> a, T t, Args... args) { a.compare_exchange_weak(t, t, args...); };
+
+template <class T, template <class> class MaybeVolatile, class... Args>
+concept HasNoexceptCompareExchangeWeak = requires(MaybeVolatile<std::atomic<T>> a, T t, Args... args) {
+  { a.compare_exchange_weak(t, t, args...) } noexcept;
+};
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t, class... MemoryOrder>
+void testBasic(MemoryOrder... memory_order) {
+  static_assert(HasVolatileCompareExchangeWeak<T, MemoryOrder...> == std::atomic<T>::is_always_lock_free);
+  static_assert(HasNoexceptCompareExchangeWeak<T, MaybeVolatile, MemoryOrder...>);
+
+  // compare pass
+  {
+    MaybeVolatile<std::atomic<T>> a(T(1.2));
+    T expected(1.2);
+    const T desired(2.3);
+    std::same_as<bool> decltype(auto) r = a.compare_exchange_weak(expected, desired, memory_order...);
+
+    // could be false spuriously
+    if (r) {
+      assert(a.load() == desired);
+    }
+    // if r is true, expected should be unmodified (1.2)
+    // if r is false, the original value of a (1.2) is written to expected
+    assert(expected == T(1.2));
+  }
+
+  // compare fail
+  {
+    MaybeVolatile<std::atomic<T>> a(T(1.2));
+    T expected(1.5);
+    const T desired(2.3);
+    std::same_as<bool> decltype(auto) r = a.compare_exchange_weak(expected, desired, memory_order...);
+
+    assert(!r);
+    assert(a.load() == T(1.2));
+
+    // bug
+    // https://github.com/llvm/llvm-project/issues/47978
+    if constexpr (!std::same_as<T, long double>) {
+      assert(expected == T(1.2));
+    }
+  }
+}
+
+// https://github.com/llvm/llvm-project/issues/47978
+template <class A, class T>
+void workaroundClangBug(A& atomic, T& expected) {
+  if constexpr (std::same_as<T, long double>) {
+    expected = atomic.load(std::memory_order::relaxed);
+  }
+}
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  testBasic<T, MaybeVolatile>();
+  testBasic<T, MaybeVolatile>(std::memory_order::relaxed);
+  testBasic<T, MaybeVolatile>(std::memory_order::relaxed, std::memory_order_relaxed);
+
+  // test success memory order release
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      // could fail spuriously, so put it in a loop
+      while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release, std::memory_order_relaxed)) {
+        workaroundClangBug(x, old_val);
+      }
+    };
+
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto store_one_arg = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      // could fail spuriously, so put it in a loop
+      while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::release)) {
+        workaroundClangBug(x, old_val);
+      }
+    };
+    test_acquire_release<T, MaybeVolatile>(store_one_arg, load);
+  }
+
+  // test success memory order acquire
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_weak(val, val, std::memory_order::acquire, std::memory_order_relaxed)) {
+        workaroundClangBug(x, val);
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_weak(val, val, std::memory_order::acquire)) {
+        workaroundClangBug(x, val);
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load_one_arg);
+  }
+
+  // test success memory order acq_rel
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      // could fail spuriously, so put it in a loop
+      while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel, std::memory_order_relaxed)) {
+        workaroundClangBug(x, old_val);
+      }
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel, std::memory_order_relaxed)) {
+        workaroundClangBug(x, val);
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto store_one_arg = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      // could fail spuriously, so put it in a loop
+      while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::acq_rel)) {
+        workaroundClangBug(x, old_val);
+      }
+    };
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_weak(val, val, std::memory_order::acq_rel)) {
+        workaroundClangBug(x, val);
+      }
+      return val;
+    };
+    test_acquire_release<T, MaybeVolatile>(store_one_arg, load_one_arg);
+  }
+
+  // test success memory seq_cst
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      // could fail spuriously, so put it in a loop
+      while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst, std::memory_order_relaxed)) {
+        workaroundClangBug(x, old_val);
+      }
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst, std::memory_order_relaxed)) {
+        workaroundClangBug(x, val);
+      }
+      return val;
+    };
+    test_seq_cst<T, MaybeVolatile>(store, load);
+
+    auto store_one_arg = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      // could fail spuriously, so put it in a loop
+      while (!x.compare_exchange_weak(old_val, new_val, std::memory_order::seq_cst, std::memory_order_relaxed)) {
+        workaroundClangBug(x, old_val);
+      }
+    };
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto val = x.load(std::memory_order::relaxed);
+      while (!x.compare_exchange_weak(val, val, std::memory_order::seq_cst, std::memory_order_relaxed)) {
+        workaroundClangBug(x, val);
+      }
+      return val;
+    };
+    test_seq_cst<T, MaybeVolatile>(store_one_arg, load_one_arg);
+  }
+
+  // test fail memory order acquire
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order_relaxed, std::memory_order_acquire);
+      assert(!r);
+      return result;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+
+    auto load_one_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order_acquire);
+      assert(!r);
+      return result;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load_one_arg);
+
+    // acq_rel replaced by acquire
+    auto load_one_arg_acq_rel = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order_acq_rel);
+      assert(!r);
+      return result;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load_one_arg_acq_rel);
+  }
+
+  // test fail memory order seq_cst
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::seq_cst); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      T unexpected(-9999.99);
+      bool r = x.compare_exchange_weak(unexpected, unexpected, std::memory_order_relaxed, std::memory_order::seq_cst);
+      assert(!r);
+      return result;
+    };
+    test_seq_cst<T, MaybeVolatile>(store, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
new file mode 100644
index 000000000000000..63162f256cec93b
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//  T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept;
+//  T exchange(T, memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileExchange = requires(volatile std::atomic<T> a, T t) { a.exchange(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileExchange<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>() = (T(0))));
+
+  // exchange
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = a.exchange(T(1.2), std::memory_order::relaxed);
+    assert(a.load() == T(1.2));
+    assert(r == T(3.1));
+  }
+
+  // memory_order::release
+  {
+    auto exchange = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) {
+      x.exchange(new_val, std::memory_order::release);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(exchange, load);
+  }
+
+  // memory_order::seq_cst
+  {
+    auto exchange_no_arg     = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.exchange(new_val); };
+    auto exchange_with_order = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) {
+      x.exchange(new_val, std::memory_order::seq_cst);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(exchange_no_arg, load);
+    test_seq_cst<T, MaybeVolatile>(exchange_with_order, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 54780e18e9bec4a..2a30ea8e2488654 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -19,29 +19,21 @@
 #include <thread>
 #include <vector>
 
+#include "test_helper.h"
 #include "test_macros.h"
-#include "make_test_thread.h"
 
 template <class T>
 concept HasVolatileFetchAdd = requires(volatile std::atomic<T> a, T t) { a.fetch_add(t); };
 
-template <class T>
-void test() {
-  static_assert(noexcept(std::declval<std::atomic<T>&>().fetch_add(T(0))));
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
   static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
 
   // fetch_add
   {
-    std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2));
-    assert(r == T(3.1));
-    assert(a.load() == T(3.1) + T(1.2));
-  }
-
-  // fetch_add volatile
-  if constexpr (std::atomic<T>::is_always_lock_free) {
-    volatile std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2));
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2), std::memory_order::relaxed);
     assert(r == T(3.1));
     assert(a.load() == T(3.1) + T(1.2));
   }
@@ -51,14 +43,14 @@ void test() {
     constexpr auto number_of_threads = 4;
     constexpr auto loop              = 1000;
 
-    std::atomic<T> at;
+    MaybeVolatile<std::atomic<T>> at;
 
     std::vector<std::thread> threads;
     threads.reserve(number_of_threads);
     for (auto i = 0; i < number_of_threads; ++i) {
       threads.emplace_back([&at]() {
         for (auto j = 0; j < loop; ++j) {
-          at.fetch_add(T(1.234));
+          at.fetch_add(T(1.234), std::memory_order::relaxed);
         }
       });
     }
@@ -77,6 +69,34 @@ void test() {
 
     assert(at.load() == times(1.234, number_of_threads * loop));
   }
+
+  // memory_order::release
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      x.fetch_add(new_val - old_val, std::memory_order::release);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+  }
+
+  // memory_order::seq_cst
+  {
+    auto fetch_add = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) { x.fetch_add(new_val - old_value); };
+    auto fetch_add_with_order = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) {
+      x.fetch_add(new_val - old_value, std::memory_order::seq_cst);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(fetch_add, load);
+    test_seq_cst<T, MaybeVolatile>(fetch_add_with_order, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index 02a42144a4692e1..5f38be7cf2a75d3 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -19,29 +19,21 @@
 #include <thread>
 #include <vector>
 
+#include "test_helper.h"
 #include "test_macros.h"
-#include "make_test_thread.h"
 
 template <class T>
 concept HasVolatileFetchSub = requires(volatile std::atomic<T> a, T t) { a.fetch_sub(t); };
 
-template <class T>
-void test() {
-  static_assert(noexcept(std::declval<std::atomic<T>&>().fetch_sub(T(0))));
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
   static_assert(HasVolatileFetchSub<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_sub(T(0))));
 
   // fetch_sub
   {
-    std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_sub(T(1.2));
-    assert(r == T(3.1));
-    assert(a.load() == T(3.1) - T(1.2));
-  }
-
-  // fetch_sub volatile
-  if constexpr (std::atomic<T>::is_always_lock_free) {
-    volatile std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a.fetch_sub(T(1.2));
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_sub(T(1.2), std::memory_order::relaxed);
     assert(r == T(3.1));
     assert(a.load() == T(3.1) - T(1.2));
   }
@@ -51,14 +43,14 @@ void test() {
     constexpr auto number_of_threads = 4;
     constexpr auto loop              = 1000;
 
-    std::atomic<T> at;
+    MaybeVolatile<std::atomic<T>> at;
 
     std::vector<std::thread> threads;
     threads.reserve(number_of_threads);
     for (auto i = 0; i < number_of_threads; ++i) {
       threads.emplace_back([&at]() {
         for (auto j = 0; j < loop; ++j) {
-          at.fetch_sub(T(1.234));
+          at.fetch_sub(T(1.234), std::memory_order::relaxed);
         }
       });
     }
@@ -77,6 +69,34 @@ void test() {
 
     assert(at.load() == accu_neg(1.234, number_of_threads * loop));
   }
+
+  // memory_order::release
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      x.fetch_sub(old_val - new_val, std::memory_order::release);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+  }
+
+  // memory_order::seq_cst
+  {
+    auto fetch_sub = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) { x.fetch_sub(old_value - new_val); };
+    auto fetch_sub_with_order = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) {
+      x.fetch_sub(old_value - new_val, std::memory_order::seq_cst);
+    };
+    auto load = [](auto& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(fetch_sub, load);
+    test_seq_cst<T, MaybeVolatile>(fetch_sub_with_order, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
new file mode 100644
index 000000000000000..b4e08154892230e
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
@@ -0,0 +1,129 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//  floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept;
+//  floating-point-type load(memory_order = memory_order::seq_cst) noexcept;
+
+#include <algorithm>
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <thread>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileLoad = requires(volatile std::atomic<T> a, T t) { a.load(); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileLoad<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().load()));
+
+  // load
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    a.store(T(1.2));
+    std::same_as<T> decltype(auto) r = a.load(std::memory_order::relaxed);
+    assert(r == T(1.2));
+  }
+
+  // memory_order::relaxed
+  {
+    constexpr auto number_of_threads = 4;
+    constexpr auto loop              = 1000;
+
+    MaybeVolatile<std::atomic<T>> at(T(-1.0));
+
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+    for (auto i = 0; i < number_of_threads; ++i) {
+      threads.emplace_back([&at, i]() {
+        for (auto j = 0; j < loop; ++j) {
+          at.store(T(i));
+        }
+      });
+    }
+
+    while (at.load(std::memory_order::relaxed) == T(-1.0)) {
+      std::this_thread::yield();
+    }
+
+    for (auto i = 0; i < loop; ++i) {
+      auto r = at.load(std::memory_order_relaxed);
+      assert(std::ranges::any_of(std::views::iota(0, number_of_threads), [r](auto i) { return r == T(i); }));
+    }
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+  }
+
+  // memory_order::comsume
+  {
+    std::unique_ptr<T> p = std::make_unique<T>(T(0.0));
+    MaybeVolatile<std::atomic<T>> at(T(0.0));
+
+    constexpr auto number_of_threads = 8;
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+
+    for (auto i = 0; i < number_of_threads; ++i) {
+      threads.emplace_back([&at, &p] {
+        while (at.load(std::memory_order::consume) == T(0.0)) {
+          std::this_thread::yield();
+        }
+        assert(*p == T(1.0)); // the write from other thread should be visible
+      });
+    }
+
+    *p = T(1.0);
+    at.store(*p, std::memory_order_release);
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+  }
+
+  // memory_order::acquire
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+  }
+
+  // memory_order::seq_cst
+  {
+    auto store           = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val); };
+    auto load_no_arg     = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    auto load_with_order = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::seq_cst); };
+    test_seq_cst<T, MaybeVolatile>(store, load_no_arg);
+    test_seq_cst<T, MaybeVolatile>(store, load_with_order);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
new file mode 100644
index 000000000000000..88c7f1c6e3bb1be
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//  operator floating-point-type() volatile noexcept;
+//  operator floating-point-type() noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(std::is_convertible_v<volatile std::atomic<T>&, T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(T(std::declval<MaybeVolatile<std::atomic<T>>&>())));
+
+  // operator float
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    T r = a;
+    assert(r == T(3.1));
+  }
+
+  // memory_order::seq_cst
+  {
+    auto store    = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val); };
+    auto op_float = [](MaybeVolatile<std::atomic<T>>& x) -> T { return x; };
+    test_seq_cst<T, MaybeVolatile>(store, op_float);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index 5a04e9e94027d4a..f48441641012dff 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -16,28 +16,20 @@
 #include <thread>
 #include <vector>
 
+#include "test_helper.h"
 #include "test_macros.h"
-#include "make_test_thread.h"
 
 template <class T>
 concept HasVolatileMinusEquals = requires(volatile std::atomic<T> a, T t) { a -= t; };
 
-template <class T>
-void test() {
-  static_assert(noexcept(std::declval<std::atomic<T>&>() -= T(0)));
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
   static_assert(HasVolatileMinusEquals<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>() -= T(0)));
 
   // -=
   {
-    std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a -= T(1.2);
-    assert(r == T(3.1) - T(1.2));
-    assert(a.load() == T(3.1) - T(1.2));
-  }
-
-  // -= volatile
-  if constexpr (std::atomic<T>::is_always_lock_free) {
-    volatile std::atomic<T> a(3.1);
+    MaybeVolatile<std::atomic<T>> a(3.1);
     std::same_as<T> decltype(auto) r = a -= T(1.2);
     assert(r == T(3.1) - T(1.2));
     assert(a.load() == T(3.1) - T(1.2));
@@ -48,7 +40,7 @@ void test() {
     constexpr auto number_of_threads = 4;
     constexpr auto loop              = 1000;
 
-    std::atomic<T> at;
+    MaybeVolatile<std::atomic<T>> at;
 
     std::vector<std::thread> threads;
     threads.reserve(number_of_threads);
@@ -74,6 +66,21 @@ void test() {
 
     assert(at.load() == accu_neg(1.234, number_of_threads * loop));
   }
+
+  // memory_order::seq_cst
+  {
+    auto minus_equals = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) { x -= (old_value - new_val); };
+    auto load         = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(minus_equals, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index 9cace80331736b8..f617ded35138ec6 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -16,28 +16,20 @@
 #include <thread>
 #include <vector>
 
+#include "test_helper.h"
 #include "test_macros.h"
-#include "make_test_thread.h"
 
 template <class T>
 concept HasVolatilePlusEquals = requires(volatile std::atomic<T> a, T t) { a += t; };
 
-template <class T>
-void test() {
-  static_assert(noexcept(std::declval<std::atomic<T>&>() += T(0)));
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
   static_assert(HasVolatilePlusEquals<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>() += T(0)));
 
   // +=
   {
-    std::atomic<T> a(3.1);
-    std::same_as<T> decltype(auto) r = a += T(1.2);
-    assert(r == T(3.1) + T(1.2));
-    assert(a.load() == T(3.1) + T(1.2));
-  }
-
-  // += volatile
-  if constexpr (std::atomic<T>::is_always_lock_free) {
-    volatile std::atomic<T> a(3.1);
+    MaybeVolatile<std::atomic<T>> a(3.1);
     std::same_as<T> decltype(auto) r = a += T(1.2);
     assert(r == T(3.1) + T(1.2));
     assert(a.load() == T(3.1) + T(1.2));
@@ -48,7 +40,7 @@ void test() {
     constexpr auto number_of_threads = 4;
     constexpr auto loop              = 1000;
 
-    std::atomic<T> at;
+    MaybeVolatile<std::atomic<T>> at;
 
     std::vector<std::thread> threads;
     threads.reserve(number_of_threads);
@@ -74,6 +66,21 @@ void test() {
 
     assert(at.load() == times(1.234, number_of_threads * loop));
   }
+
+  // memory_order::seq_cst
+  {
+    auto plus_equals = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) { x += (new_val - old_value); };
+    auto load        = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(plus_equals, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
new file mode 100644
index 000000000000000..cbfbbd3bc091266
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
@@ -0,0 +1,104 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept;
+// void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept;
+
+#include <algorithm>
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <thread>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileStore = requires(volatile std::atomic<T> a, T t) { a.store(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileStore<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().store(T(0))));
+
+  // store
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    a.store(T(1.2), std::memory_order::relaxed);
+    assert(a.load() == T(1.2));
+  }
+
+  // memory_order::relaxed
+  {
+    constexpr auto number_of_threads = 4;
+    constexpr auto loop              = 1000;
+
+    MaybeVolatile<std::atomic<T>> at(T(-1.0));
+
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+    for (auto i = 0; i < number_of_threads; ++i) {
+      threads.emplace_back([&at, i]() {
+        for (auto j = 0; j < loop; ++j) {
+          at.store(T(i), std::memory_order_relaxed);
+        }
+      });
+    }
+
+    while (at.load() == T(-1.0)) {
+      std::this_thread::yield();
+    }
+
+    for (auto i = 0; i < loop; ++i) {
+      auto r = at.load();
+      assert(std::ranges::any_of(std::views::iota(0, number_of_threads), [r](auto i) { return r == T(i); }));
+    }
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+  }
+
+  // memory_order::release
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+  }
+
+  // memory_order::seq_cst
+  {
+    auto store_no_arg     = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val); };
+    auto store_with_order = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) {
+      x.store(new_val, std::memory_order::seq_cst);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(store_no_arg, load);
+    test_seq_cst<T, MaybeVolatile>(store_with_order, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
new file mode 100644
index 000000000000000..fac869b1d32ab55
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
@@ -0,0 +1,96 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_ATOMICS_ATOMICS_TYPES_FLOAT_TEST_HELPER_H
+#define TEST_STD_ATOMICS_ATOMICS_TYPES_FLOAT_TEST_HELPER_H
+
+#include <atomic>
+#include <cassert>
+#include <thread>
+#include <vector>
+
+// Test that all threads see the exact same sequence of events
+// Test will pass 100% if store_op and load_op are correctly
+// affecting the memory with seq_cst order
+template <class T, template <class> class MaybeVolatile, class StoreOp, class LoadOp>
+void test_seq_cst(StoreOp store_op, LoadOp load_op) {
+  for (int i = 0; i < 100; ++i) {
+    T old_value = 0.0;
+    T new_value = 1.0;
+
+    MaybeVolatile<std::atomic<T>> x(old_value);
+    MaybeVolatile<std::atomic<T>> y(old_value);
+
+    std::atomic_bool x_update_first(false);
+    std::atomic_bool y_update_first(false);
+
+    std::thread t1([&] { store_op(x, old_value, new_value); });
+
+    std::thread t2([&] { store_op(y, old_value, new_value); });
+
+    std::thread t3([&] {
+      while (load_op(x) != new_value) {
+        std::this_thread::yield();
+      }
+      if (load_op(y) != new_value) {
+        x_update_first.store(true, std::memory_order_relaxed);
+      }
+    });
+
+    std::thread t4([&] {
+      while (load_op(y) != new_value) {
+        std::this_thread::yield();
+      }
+      if (load_op(x) != new_value) {
+        y_update_first.store(true, std::memory_order_relaxed);
+      }
+    });
+
+    t1.join();
+    t2.join();
+    t3.join();
+    t4.join();
+    assert(!(x_update_first && y_update_first));
+  }
+}
+
+// Test that all writes before the store are seen by other threads after the load
+// Test will pass 100% if store_op and load_op are correctly
+// affecting the memory with acquire-release order
+template <class T, template <class> class MaybeVolatile, class StoreOp, class LoadOp>
+void test_acquire_release(StoreOp store_op, LoadOp load_op) {
+  for (auto i = 0; i < 100; ++i) {
+    T old_value = 0.0;
+    T new_value = 1.0;
+
+    MaybeVolatile<std::atomic<T>> at(old_value);
+    int non_atomic = 5;
+
+    constexpr auto number_of_threads = 4;
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+
+    for (auto j = 0; j < number_of_threads; ++j) {
+      threads.emplace_back([&at, &non_atomic, load_op, new_value] {
+        while (load_op(at) != new_value) {
+          std::this_thread::yield();
+        }
+        assert(non_atomic == 6);
+      });
+    }
+
+    non_atomic = 6;
+    store_op(at, old_value, new_value);
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+  }
+}
+
+#endif // TEST_STD_ATOMICS_ATOMICS_TYPES_FLOAT_TEST_HELPER_H
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
new file mode 100644
index 000000000000000..a697a6706de503c
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;
+// void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileWait = requires(volatile std::atomic<T> a, T t) { a.wait(T()); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileWait<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().wait(T())));
+
+  // wait different value
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    a.wait(T(1.1), std::memory_order::relaxed);
+  }
+
+  // memory_order::acquire
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
+    auto load  = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      x.wait(T(9999.999), std::memory_order::acquire);
+      return result;
+    };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+  }
+
+  // memory_order::seq_cst
+  {
+    auto store       = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val); };
+    auto load_no_arg = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      x.wait(T(9999.999));
+      return result;
+    };
+    auto load_with_order = [](MaybeVolatile<std::atomic<T>>& x) {
+      auto result = x.load(std::memory_order::relaxed);
+      x.wait(T(9999.999), std::memory_order::seq_cst);
+      return result;
+    };
+    test_seq_cst<T, MaybeVolatile>(store, load_no_arg);
+    test_seq_cst<T, MaybeVolatile>(store, load_with_order);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}

>From 180708c8253771716428e52f4c9f76022b1965be Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 11 Oct 2023 23:47:09 +0100
Subject: [PATCH 05/18] more tests

---
 .../atomics.types.float/notify_all.pass.cpp   | 94 +++++++++++++++++++
 .../atomics.types.float/notify_one.pass.cpp   | 80 ++++++++++++++++
 .../atomics.types.float/test_helper.h         |  2 +-
 .../atomics.types.float/wait.pass.cpp         | 37 +++++++-
 4 files changed, 210 insertions(+), 3 deletions(-)
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
new file mode 100644
index 000000000000000..0c4898e0b121c26
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
@@ -0,0 +1,94 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//  void notify_all() volatile noexcept;
+//  void notify_all() noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileNotifyAll = requires(volatile std::atomic<T> a, T t) { a.notify_all(); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileNotifyAll<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().notify_all()));
+
+  // bug?? wait can also fail for long double ??
+  // should x87 80bit long double work at all?
+  if constexpr (!std::same_as<T, long double>) {
+    for (auto i = 0; i < 100; ++i) {
+      const T old = 3.1;
+      MaybeVolatile<std::atomic<T>> a(old);
+
+      bool done                      = false;
+      std::atomic<int> started_num   = 0;
+      std::atomic<int> wait_done_num = 0;
+
+      constexpr auto number_of_threads = 8;
+      std::vector<std::thread> threads;
+      threads.reserve(number_of_threads);
+
+      for (auto j = 0; j < number_of_threads; ++j) {
+        threads.emplace_back([&a, &started_num, old, &done, &wait_done_num] {
+          started_num.fetch_add(1, std::memory_order::relaxed);
+
+          a.wait(old);
+          wait_done_num.fetch_add(1, std::memory_order::relaxed);
+
+          // likely to fail if wait did not block
+          assert(done);
+        });
+      }
+
+      while (started_num.load(std::memory_order::relaxed) != number_of_threads) {
+        std::this_thread::yield();
+      }
+
+      std::this_thread::sleep_for(std::chrono::milliseconds(1));
+
+      done = true;
+      a.store(T(9.9));
+      a.notify_all();
+
+      // notify_all should unblock all the threads so that the loop below won't stuck
+      while (wait_done_num.load(std::memory_order::relaxed) != number_of_threads) {
+        std::this_thread::yield();
+      }
+
+      for (auto& thread : threads) {
+        thread.join();
+      }
+    }
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
new file mode 100644
index 000000000000000..a6265f78cd11572
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+//  void notify_one() volatile noexcept;
+//  void notify_one() noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileNotifyOne = requires(volatile std::atomic<T> a, T t) { a.notify_one(); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileNotifyOne<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().notify_one()));
+
+
+  // bug?? wait can also fail for long double ??
+  // should x87 80bit long double work at all?
+  if constexpr (!std::same_as<T, long double>) {
+    for (auto i = 0; i < 100; ++i) {
+      const T old = 3.1;
+      MaybeVolatile<std::atomic<T>> a(old);
+
+      std::atomic_bool started = false;
+      bool done                = false;
+
+      std::thread t([&a, &started, old, &done] {
+        started.store(true, std::memory_order::relaxed);
+
+        a.wait(old);
+
+        // likely to fail if wait did not block
+        assert(done);
+      });
+
+      while (!started.load(std::memory_order::relaxed)) {
+        std::this_thread::yield();
+      }
+
+      std::this_thread::sleep_for(std::chrono::milliseconds(1));
+
+      done = true;
+      a.store(T(9.9));
+      a.notify_one();
+      t.join();
+    }
+  }
+
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
index fac869b1d32ab55..5ccb9cb86a1803e 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
@@ -71,7 +71,7 @@ void test_acquire_release(StoreOp store_op, LoadOp load_op) {
     MaybeVolatile<std::atomic<T>> at(old_value);
     int non_atomic = 5;
 
-    constexpr auto number_of_threads = 4;
+    constexpr auto number_of_threads = 8;
     std::vector<std::thread> threads;
     threads.reserve(number_of_threads);
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
index a697a6706de503c..94b915dd236fd66 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
@@ -28,12 +28,45 @@ void testImpl() {
   static_assert(HasVolatileWait<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().wait(T())));
 
-  // wait different value
+  // wait with different value
   {
-    MaybeVolatile<std::atomic<T>> a(3.1);
+    MaybeVolatile<std::atomic<T>> a(T(3.1));
     a.wait(T(1.1), std::memory_order::relaxed);
   }
 
+  // equal at the beginning and changed later
+  // bug?? wait can also fail for long double ??
+  // should x87 80bit long double work at all?
+  if constexpr (!std::same_as<T, long double>) {
+    for (auto i = 0; i < 100; ++i) {
+      const T old = 3.1;
+      MaybeVolatile<std::atomic<T>> a(old);
+
+      std::atomic_bool started = false;
+      bool done                = false;
+
+      std::thread t([&a, &started, old, &done] {
+        started.store(true, std::memory_order::relaxed);
+
+        a.wait(old);
+
+        // likely to fail if wait did not block
+        assert(done);
+      });
+
+      while (!started.load(std::memory_order::relaxed)) {
+        std::this_thread::yield();
+      }
+
+      std::this_thread::sleep_for(std::chrono::milliseconds(1));
+
+      done = true;
+      a.store(T(9.9));
+      a.notify_all();
+      t.join();
+    }
+  }
+
   // memory_order::acquire
   {
     auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };

>From f4f59a52a240f71d4aa578e359ad8ae3ee4e9dfe Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Thu, 12 Oct 2023 00:05:21 +0100
Subject: [PATCH 06/18] shadow

---
 .../atomics.types.generic/atomics.types.float/load.pass.cpp     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
index b4e08154892230e..b80e84a2c75fe3f 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
@@ -61,7 +61,7 @@ void testImpl() {
 
     for (auto i = 0; i < loop; ++i) {
       auto r = at.load(std::memory_order_relaxed);
-      assert(std::ranges::any_of(std::views::iota(0, number_of_threads), [r](auto i) { return r == T(i); }));
+      assert(std::ranges::any_of(std::views::iota(0, number_of_threads), [r](auto j) { return r == T(j); }));
     }
 
     for (auto& thread : threads) {

>From 13619ef675119dda04ef905c47069c70a4376e88 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Fri, 13 Oct 2023 13:06:17 +0100
Subject: [PATCH 07/18] CI

---
 libcxx/test/libcxx/transitive_includes/cxx03.csv            | 2 ++
 libcxx/test/libcxx/transitive_includes/cxx11.csv            | 2 ++
 libcxx/test/libcxx/transitive_includes/cxx14.csv            | 2 ++
 libcxx/test/libcxx/transitive_includes/cxx17.csv            | 2 ++
 libcxx/test/libcxx/transitive_includes/cxx20.csv            | 2 ++
 libcxx/test/libcxx/transitive_includes/cxx23.csv            | 6 ++++++
 libcxx/test/libcxx/transitive_includes/cxx26.csv            | 6 ++++++
 .../atomics.types.float/notify_one.pass.cpp                 | 2 --
 8 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index f6aeb837a7292f6..b662f79d6e0a9b7 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -54,6 +54,7 @@ atomic cmath
 atomic compare
 atomic cstddef
 atomic cstdint
+atomic cstdio
 atomic cstdlib
 atomic cstring
 atomic ctime
@@ -800,6 +801,7 @@ stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
 stop_token cstdint
+stop_token cstdio
 stop_token cstring
 stop_token ctime
 stop_token iosfwd
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 08fd94393f47320..016b2d23c34f6b1 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -54,6 +54,7 @@ atomic cmath
 atomic compare
 atomic cstddef
 atomic cstdint
+atomic cstdio
 atomic cstdlib
 atomic cstring
 atomic ctime
@@ -806,6 +807,7 @@ stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
 stop_token cstdint
+stop_token cstdio
 stop_token cstring
 stop_token ctime
 stop_token iosfwd
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 33384a628e65c01..78342c38ca50dfb 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -54,6 +54,7 @@ atomic cmath
 atomic compare
 atomic cstddef
 atomic cstdint
+atomic cstdio
 atomic cstdlib
 atomic cstring
 atomic ctime
@@ -808,6 +809,7 @@ stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
 stop_token cstdint
+stop_token cstdio
 stop_token cstring
 stop_token ctime
 stop_token iosfwd
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 33384a628e65c01..78342c38ca50dfb 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -54,6 +54,7 @@ atomic cmath
 atomic compare
 atomic cstddef
 atomic cstdint
+atomic cstdio
 atomic cstdlib
 atomic cstring
 atomic ctime
@@ -808,6 +809,7 @@ stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
 stop_token cstdint
+stop_token cstdio
 stop_token cstring
 stop_token ctime
 stop_token iosfwd
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 8f6e8dd646df583..d662a62d208450d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -53,6 +53,7 @@ atomic cmath
 atomic compare
 atomic cstddef
 atomic cstdint
+atomic cstdio
 atomic cstdlib
 atomic cstring
 atomic ctime
@@ -813,6 +814,7 @@ stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
 stop_token cstdint
+stop_token cstdio
 stop_token cstring
 stop_token ctime
 stop_token iosfwd
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index d0d858056b1b00d..0c8a99a5f8786f2 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -1,6 +1,7 @@
 algorithm climits
 algorithm cstddef
 algorithm cstdint
+algorithm cstdio
 algorithm cstring
 algorithm ctime
 algorithm cwchar
@@ -30,6 +31,7 @@ array stdexcept
 array version
 atomic cstddef
 atomic cstdint
+atomic cstdio
 atomic cstdlib
 atomic cstring
 atomic ctime
@@ -123,6 +125,7 @@ condition_variable atomic
 condition_variable cerrno
 condition_variable cstddef
 condition_variable cstdint
+condition_variable cstdio
 condition_variable cstring
 condition_variable ctime
 condition_variable iosfwd
@@ -299,6 +302,7 @@ ios cerrno
 ios clocale
 ios cstddef
 ios cstdint
+ios cstdio
 ios cstdlib
 ios cstring
 ios ctime
@@ -427,6 +431,7 @@ numeric climits
 numeric cmath
 numeric cstddef
 numeric cstdint
+numeric cstdio
 numeric cstring
 numeric ctime
 numeric execution
@@ -585,6 +590,7 @@ stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
 stop_token cstdint
+stop_token cstdio
 stop_token cstring
 stop_token ctime
 stop_token iosfwd
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index d0d858056b1b00d..0c8a99a5f8786f2 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -1,6 +1,7 @@
 algorithm climits
 algorithm cstddef
 algorithm cstdint
+algorithm cstdio
 algorithm cstring
 algorithm ctime
 algorithm cwchar
@@ -30,6 +31,7 @@ array stdexcept
 array version
 atomic cstddef
 atomic cstdint
+atomic cstdio
 atomic cstdlib
 atomic cstring
 atomic ctime
@@ -123,6 +125,7 @@ condition_variable atomic
 condition_variable cerrno
 condition_variable cstddef
 condition_variable cstdint
+condition_variable cstdio
 condition_variable cstring
 condition_variable ctime
 condition_variable iosfwd
@@ -299,6 +302,7 @@ ios cerrno
 ios clocale
 ios cstddef
 ios cstdint
+ios cstdio
 ios cstdlib
 ios cstring
 ios ctime
@@ -427,6 +431,7 @@ numeric climits
 numeric cmath
 numeric cstddef
 numeric cstdint
+numeric cstdio
 numeric cstring
 numeric ctime
 numeric execution
@@ -585,6 +590,7 @@ stdexcept iosfwd
 stop_token atomic
 stop_token cstddef
 stop_token cstdint
+stop_token cstdio
 stop_token cstring
 stop_token ctime
 stop_token iosfwd
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
index a6265f78cd11572..b7827143d701679 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
@@ -28,7 +28,6 @@ void testImpl() {
   static_assert(HasVolatileNotifyOne<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().notify_one()));
 
-
   // bug?? wait can also fail for long double ??
   // should x87 80bit long double work at all?
   if constexpr (!std::same_as<T, long double>) {
@@ -60,7 +59,6 @@ void testImpl() {
       t.join();
     }
   }
-
 }
 
 template <class T>

>From 869f288529b1d58e159576ab5cd6cd846d56dc03 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Fri, 13 Oct 2023 20:08:36 +0100
Subject: [PATCH 08/18] add linker flag

---
 .../{locakfree.pass.cpp => lockfree.pass.cpp}                 | 0
 .../atomics.types.generic/atomics.types.float/assign.pass.cpp | 1 +
 .../atomics.types.float/compare_exchange_strong.pass.cpp      | 1 +
 .../atomics.types.float/compare_exchange_weak.pass.cpp        | 1 +
 .../atomics.types.generic/atomics.types.float/ctor.pass.cpp   | 1 +
 .../atomics.types.float/exchange.pass.cpp                     | 1 +
 .../atomics.types.float/fetch_add.pass.cpp                    | 1 +
 .../atomics.types.float/fetch_sub.pass.cpp                    | 1 +
 .../atomics.types.generic/atomics.types.float/load.pass.cpp   | 1 +
 .../atomics.types.float/lockfree.pass.cpp                     | 1 +
 .../atomics.types.float/notify_all.pass.cpp                   | 1 +
 .../atomics.types.float/notify_one.pass.cpp                   | 1 +
 .../atomics.types.float/operator.float.pass.cpp               | 1 +
 .../atomics.types.float/operator.minus_equals.pass.cpp        | 1 +
 .../atomics.types.float/operator.plus_equals.pass.cpp         | 1 +
 .../atomics.types.generic/atomics.types.float/store.pass.cpp  | 1 +
 libcxx/utils/libcxx/test/features.py                          | 4 ++++
 17 files changed, 19 insertions(+)
 rename libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/{locakfree.pass.cpp => lockfree.pass.cpp} (100%)

diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/locakfree.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
similarity index 100%
rename from libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/locakfree.pass.cpp
rename to libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
index 4f9383c0b934c37..6f1bc734d5dabd0 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //  floating-point-type operator=(floating-point-type) volatile noexcept;
 //  floating-point-type operator=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
index b1f219865d8f95c..a7064eef01bf3ff 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // bool compare_exchange_strong(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
index d320fdefc081289..1e2affe696952a7 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // bool compare_exchange_weak(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
index 16df7ff23488759..7a3b08c7934c114 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // constexpr atomic() noexcept;
 // constexpr atomic(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
index 63162f256cec93b..bbaef97d4075e12 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //  T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept;
 //  T exchange(T, memory_order = memory_order::seq_cst) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 2a30ea8e2488654..9bca92ef5de2868 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // floating-point-type fetch_add(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index 5f38be7cf2a75d3..46e113a7b7b4aff 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // floating-point-type fetch_sub(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
index b80e84a2c75fe3f..78dcf5881328adc 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //  floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept;
 //  floating-point-type load(memory_order = memory_order::seq_cst) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
index b632df79c330486..62c5eb17e81538e 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //   static constexpr bool is_always_lock_free = implementation-defined;
 //   bool is_lock_free() const volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
index 0c4898e0b121c26..9c9bc2085324bcd 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //  void notify_all() volatile noexcept;
 //  void notify_all() noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
index b7827143d701679..97d7c1a41c3b4c9 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //  void notify_one() volatile noexcept;
 //  void notify_one() noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
index 88c7f1c6e3bb1be..f6d6d8626049654 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //  operator floating-point-type() volatile noexcept;
 //  operator floating-point-type() noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index f48441641012dff..7be7570092622b9 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // floating-point-type operator-=(floating-point-type) volatile noexcept;
 // floating-point-type operator-=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index f617ded35138ec6..acce07c748dc8aa 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // floating-point-type operator+=(floating-point-type) volatile noexcept;
 // floating-point-type operator+=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
index cbfbbd3bc091266..276086deefa8464 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept;
 // void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept;
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 3779af1094d5d0f..b72ca6fa6bedc8c 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -94,6 +94,10 @@ def _getSuitableClangTidy(cfg):
         name="verify-support",
         when=lambda cfg: hasCompileFlag(cfg, "-Xclang -verify-ignore-unexpected"),
     ),
+    Feature(
+        name="has-latomic",
+        when=lambda cfg: hasCompileFlag(cfg, "-latomic"),
+    ),
     Feature(
         name="non-lockfree-atomics",
         when=lambda cfg: sourceBuilds(

>From 4b1e42d4472aab173336b9f320b2752374852005 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Fri, 13 Oct 2023 21:12:32 +0100
Subject: [PATCH 09/18] CI

---
 libcxx/include/__atomic/atomic.h                            | 4 +++-
 .../atomics.types.float/lockfree.pass.cpp                   | 1 +
 .../atomics.types.float/assign.pass.cpp                     | 2 ++
 .../atomics.types.float/compare_exchange_strong.pass.cpp    | 5 ++++-
 .../atomics.types.float/compare_exchange_weak.pass.cpp      | 5 ++++-
 .../atomics.types.generic/atomics.types.float/ctor.pass.cpp | 2 ++
 .../atomics.types.float/exchange.pass.cpp                   | 5 ++++-
 .../atomics.types.float/fetch_add.pass.cpp                  | 2 ++
 .../atomics.types.float/fetch_sub.pass.cpp                  | 2 ++
 .../atomics.types.generic/atomics.types.float/load.pass.cpp | 5 ++++-
 .../atomics.types.float/lockfree.pass.cpp                   | 2 ++
 .../atomics.types.float/notify_all.pass.cpp                 | 5 ++++-
 .../atomics.types.float/notify_one.pass.cpp                 | 5 ++++-
 .../atomics.types.float/operator.float.pass.cpp             | 5 ++++-
 .../atomics.types.float/operator.minus_equals.pass.cpp      | 2 ++
 .../atomics.types.float/operator.plus_equals.pass.cpp       | 2 ++
 .../atomics.types.float/store.pass.cpp                      | 5 ++++-
 .../atomics.types.generic/atomics.types.float/wait.pass.cpp | 6 +++++-
 18 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index c4159dcfb6ffdb2..1cc91c44458b30d 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -197,7 +197,9 @@ struct atomic<_Tp> : public __atomic_base<_Tp> {
     atomic& operator=(const atomic&)          = delete;
     atomic& operator=(const atomic&) volatile = delete;
 
-    _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept {
+    _LIBCPP_HIDE_FROM_ABI _Tp operator=(_Tp __d) volatile noexcept
+      requires __base::is_always_lock_free
+    {
         __base::store(__d);
         return __d;
     }
diff --git a/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp b/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
index 5388ae1c6710fb9..e63c8911b33a3b6 100644
--- a/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
+++ b/libcxx/test/libcxx/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 //   static constexpr bool is_always_lock_free = implementation-defined;
 //   bool is_lock_free() const volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
index 6f1bc734d5dabd0..f5e3682aa7ae260 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 //  floating-point-type operator=(floating-point-type) volatile noexcept;
 //  floating-point-type operator=(floating-point-type) noexcept;
@@ -15,6 +16,7 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
 
 #include "test_helper.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
index a7064eef01bf3ff..88af3e4c572fa03 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // bool compare_exchange_strong(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
@@ -21,6 +22,7 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
 
 #include "test_helper.h"
 #include "test_macros.h"
@@ -36,7 +38,8 @@ concept HasNoexceptCompareExchangeStrong = requires(MaybeVolatile<std::atomic<T>
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t, class... MemoryOrder>
 void testBasic(MemoryOrder... memory_order) {
-  static_assert(HasVolatileCompareExchangeStrong<T, MemoryOrder...> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileCompareExchangeStrong<T, MemoryOrder...> == std::atomic<T>::is_always_lock_free);
   static_assert(HasNoexceptCompareExchangeStrong<T, MaybeVolatile, MemoryOrder...>);
 
   // compare pass
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
index 1e2affe696952a7..81354a2d193c025 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // bool compare_exchange_weak(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
@@ -21,6 +22,7 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
 
 #include "test_helper.h"
 #include "test_macros.h"
@@ -36,7 +38,8 @@ concept HasNoexceptCompareExchangeWeak = requires(MaybeVolatile<std::atomic<T>>
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t, class... MemoryOrder>
 void testBasic(MemoryOrder... memory_order) {
-  static_assert(HasVolatileCompareExchangeWeak<T, MemoryOrder...> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileCompareExchangeWeak<T, MemoryOrder...> == std::atomic<T>::is_always_lock_free);
   static_assert(HasNoexceptCompareExchangeWeak<T, MaybeVolatile, MemoryOrder...>);
 
   // compare pass
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
index 7a3b08c7934c114..8dcff686dd02a6b 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // constexpr atomic() noexcept;
 // constexpr atomic(floating-point-type) noexcept;
@@ -14,6 +15,7 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
 
 #include "test_macros.h"
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
index bbaef97d4075e12..16b8bcb06a77957 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 //  T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept;
 //  T exchange(T, memory_order = memory_order::seq_cst) noexcept;
@@ -15,6 +16,7 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
 
 #include "test_helper.h"
 #include "test_macros.h"
@@ -24,7 +26,8 @@ concept HasVolatileExchange = requires(volatile std::atomic<T> a, T t) { a.excha
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
-  static_assert(HasVolatileExchange<T> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileExchange<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>() = (T(0))));
 
   // exchange
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 9bca92ef5de2868..9f5c7172a57e9c5 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // floating-point-type fetch_add(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
@@ -18,6 +19,7 @@
 #include <cassert>
 #include <concepts>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index 46e113a7b7b4aff..9f0b8b5a8f595b2 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // floating-point-type fetch_sub(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
@@ -18,6 +19,7 @@
 #include <cassert>
 #include <concepts>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
index 78dcf5881328adc..61052b3da4f7dc9 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 //  floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept;
 //  floating-point-type load(memory_order = memory_order::seq_cst) noexcept;
@@ -18,6 +19,7 @@
 #include <concepts>
 #include <ranges>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
@@ -28,7 +30,8 @@ concept HasVolatileLoad = requires(volatile std::atomic<T> a, T t) { a.load(); }
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
-  static_assert(HasVolatileLoad<T> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileLoad<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().load()));
 
   // load
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
index 62c5eb17e81538e..23e032d3fd7decb 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 //   static constexpr bool is_always_lock_free = implementation-defined;
 //   bool is_lock_free() const volatile noexcept;
@@ -15,6 +16,7 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
 
 #include "test_macros.h"
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
index 9c9bc2085324bcd..4f9f3b0f9ab821d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 //  void notify_all() volatile noexcept;
 //  void notify_all() noexcept;
@@ -16,6 +17,7 @@
 #include <cassert>
 #include <concepts>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
@@ -26,7 +28,8 @@ concept HasVolatileNotifyAll = requires(volatile std::atomic<T> a, T t) { a.noti
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
-  static_assert(HasVolatileNotifyAll<T> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileNotifyAll<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().notify_all()));
 
   // bug?? wait can also fail for long double ??
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
index 97d7c1a41c3b4c9..f5b60cf95ea7c08 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 //  void notify_one() volatile noexcept;
 //  void notify_one() noexcept;
@@ -16,6 +17,7 @@
 #include <cassert>
 #include <concepts>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
@@ -26,7 +28,8 @@ concept HasVolatileNotifyOne = requires(volatile std::atomic<T> a, T t) { a.noti
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
-  static_assert(HasVolatileNotifyOne<T> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileNotifyOne<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().notify_one()));
 
   // bug?? wait can also fail for long double ??
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
index f6d6d8626049654..2783bb82d555e6c 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 //  operator floating-point-type() volatile noexcept;
 //  operator floating-point-type() noexcept;
@@ -15,13 +16,15 @@
 #include <atomic>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
 
 #include "test_helper.h"
 #include "test_macros.h"
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
-  static_assert(std::is_convertible_v<volatile std::atomic<T>&, T> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(std::is_convertible_v<volatile std::atomic<T>&, T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(T(std::declval<MaybeVolatile<std::atomic<T>>&>())));
 
   // operator float
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index 7be7570092622b9..4b83eed040efa92 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // floating-point-type operator-=(floating-point-type) volatile noexcept;
 // floating-point-type operator-=(floating-point-type) noexcept;
@@ -15,6 +16,7 @@
 #include <cassert>
 #include <concepts>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index acce07c748dc8aa..ee420856cd29589 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // floating-point-type operator+=(floating-point-type) volatile noexcept;
 // floating-point-type operator+=(floating-point-type) noexcept;
@@ -15,6 +16,7 @@
 #include <cassert>
 #include <concepts>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
index 276086deefa8464..cab2110b6afae80 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
@@ -8,6 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
 
 // void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept;
 // void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept;
@@ -18,6 +19,7 @@
 #include <concepts>
 #include <ranges>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
@@ -28,7 +30,8 @@ concept HasVolatileStore = requires(volatile std::atomic<T> a, T t) { a.store(t)
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
-  static_assert(HasVolatileStore<T> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileStore<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().store(T(0))));
 
   // store
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
index 94b915dd236fd66..a0f8636e4d4b7b3 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;
 // void wait(T old, memory_order order = memory_order::seq_cst) const noexcept;
@@ -15,6 +17,7 @@
 #include <cassert>
 #include <concepts>
 #include <thread>
+#include <type_traits>
 #include <vector>
 
 #include "test_helper.h"
@@ -25,7 +28,8 @@ concept HasVolatileWait = requires(volatile std::atomic<T> a, T t) { a.wait(T())
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
-  static_assert(HasVolatileWait<T> == std::atomic<T>::is_always_lock_free);
+  // Uncomment the test after P1831R1 is implemented
+  // static_assert(HasVolatileWait<T> == std::atomic<T>::is_always_lock_free);
   static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().wait(T())));
 
   // wait with different value

>From 1a6898830b2a0d4cc04dac3ced726d3f41d36791 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Fri, 13 Oct 2023 22:01:52 +0100
Subject: [PATCH 10/18] volatile

---
 .../atomics.types.generic/atomics.types.float/assign.pass.cpp   | 2 +-
 .../atomics.types.float/compare_exchange_strong.pass.cpp        | 2 +-
 .../atomics.types.float/compare_exchange_weak.pass.cpp          | 2 +-
 .../atomics.types.generic/atomics.types.float/ctor.pass.cpp     | 2 +-
 .../atomics.types.generic/atomics.types.float/exchange.pass.cpp | 2 +-
 .../atomics.types.float/fetch_add.pass.cpp                      | 2 +-
 .../atomics.types.float/fetch_sub.pass.cpp                      | 2 +-
 .../atomics.types.generic/atomics.types.float/load.pass.cpp     | 2 +-
 .../atomics.types.generic/atomics.types.float/lockfree.pass.cpp | 2 +-
 .../atomics.types.float/notify_all.pass.cpp                     | 2 +-
 .../atomics.types.float/notify_one.pass.cpp                     | 2 +-
 .../atomics.types.float/operator.float.pass.cpp                 | 2 +-
 .../atomics.types.float/operator.minus_equals.pass.cpp          | 2 +-
 .../atomics.types.float/operator.plus_equals.pass.cpp           | 2 +-
 .../atomics.types.generic/atomics.types.float/store.pass.cpp    | 2 +-
 .../atomics.types.generic/atomics.types.float/wait.pass.cpp     | 2 +-
 16 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
index f5e3682aa7ae260..29fa0172d006d51 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 //  floating-point-type operator=(floating-point-type) volatile noexcept;
 //  floating-point-type operator=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
index 88af3e4c572fa03..6f349c002776457 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // bool compare_exchange_strong(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
index 81354a2d193c025..3c11f81f084eb00 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // bool compare_exchange_weak(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
index 8dcff686dd02a6b..e7b9c8ddf654782 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // constexpr atomic() noexcept;
 // constexpr atomic(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
index 16b8bcb06a77957..f076e34bca92b4d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 //  T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept;
 //  T exchange(T, memory_order = memory_order::seq_cst) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 9f5c7172a57e9c5..7734c829326277a 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // floating-point-type fetch_add(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index 9f0b8b5a8f595b2..fddd85b0ed5a8af 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // floating-point-type fetch_sub(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
index 61052b3da4f7dc9..36535cd49f58baf 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 //  floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept;
 //  floating-point-type load(memory_order = memory_order::seq_cst) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
index 23e032d3fd7decb..79b1a517de27d4d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 //   static constexpr bool is_always_lock_free = implementation-defined;
 //   bool is_lock_free() const volatile noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
index 4f9f3b0f9ab821d..462c1e429856b67 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 //  void notify_all() volatile noexcept;
 //  void notify_all() noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
index f5b60cf95ea7c08..c3a4639698bb09d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 //  void notify_one() volatile noexcept;
 //  void notify_one() noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
index 2783bb82d555e6c..9da7b23cd74c708 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 //  operator floating-point-type() volatile noexcept;
 //  operator floating-point-type() noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index 4b83eed040efa92..389d7bdfed106c5 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // floating-point-type operator-=(floating-point-type) volatile noexcept;
 // floating-point-type operator-=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index ee420856cd29589..bdafae759fc9f9d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // floating-point-type operator+=(floating-point-type) volatile noexcept;
 // floating-point-type operator+=(floating-point-type) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
index cab2110b6afae80..93a7e17dd4c900c 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
@@ -8,7 +8,7 @@
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 
 // void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept;
 // void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
index a0f8636e4d4b7b3..2b4eda520178741 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 // UNSUPPORTED: no-threads
 // UNSUPPORTED: c++03, c++11, c++14, c++17
-// ADDITIONAL_COMPILE_FLAGS: -Wno-volatile
+
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
 // void wait(T old, memory_order order = memory_order::seq_cst) const volatile noexcept;

>From a3ca6d23174dcf935aa759ab08986dcd0834a2f8 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Fri, 13 Oct 2023 22:23:09 +0100
Subject: [PATCH 11/18] gcc

---
 .../atomics.types.generic/atomics.types.float/store.pass.cpp    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
index 93a7e17dd4c900c..7957e7965ee5c66 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
@@ -64,7 +64,7 @@ void testImpl() {
 
     for (auto i = 0; i < loop; ++i) {
       auto r = at.load();
-      assert(std::ranges::any_of(std::views::iota(0, number_of_threads), [r](auto i) { return r == T(i); }));
+      assert(std::ranges::any_of(std::views::iota(0, number_of_threads), [r](auto j) { return r == T(j); }));
     }
 
     for (auto& thread : threads) {

>From 1171750dcc33cb0aed2bb70eea67dc617ce1b583 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Fri, 13 Oct 2023 23:07:42 +0100
Subject: [PATCH 12/18] clang format

---
 .../atomics.types.generic/atomics.types.float/assign.pass.cpp    | 1 -
 .../atomics.types.float/compare_exchange_strong.pass.cpp         | 1 -
 .../atomics.types.float/compare_exchange_weak.pass.cpp           | 1 -
 .../atomics.types.generic/atomics.types.float/ctor.pass.cpp      | 1 -
 .../atomics.types.generic/atomics.types.float/exchange.pass.cpp  | 1 -
 .../atomics.types.generic/atomics.types.float/fetch_add.pass.cpp | 1 -
 .../atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp | 1 -
 .../atomics.types.generic/atomics.types.float/load.pass.cpp      | 1 -
 .../atomics.types.generic/atomics.types.float/lockfree.pass.cpp  | 1 -
 .../atomics.types.float/notify_all.pass.cpp                      | 1 -
 .../atomics.types.float/notify_one.pass.cpp                      | 1 -
 .../atomics.types.float/operator.float.pass.cpp                  | 1 -
 .../atomics.types.float/operator.minus_equals.pass.cpp           | 1 -
 .../atomics.types.float/operator.plus_equals.pass.cpp            | 1 -
 .../atomics.types.generic/atomics.types.float/store.pass.cpp     | 1 -
 15 files changed, 15 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
index 29fa0172d006d51..b92d87beb06ca32 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 //  floating-point-type operator=(floating-point-type) volatile noexcept;
 //  floating-point-type operator=(floating-point-type) noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
index 6f349c002776457..6b3103c25bdd452 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // bool compare_exchange_strong(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
 // bool compare_exchange_strong(T& expected, T desired,
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
index 3c11f81f084eb00..c5bff48480feb70 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // bool compare_exchange_weak(T& expected, T desired,
 //                            memory_order success, memory_order failure) volatile noexcept;
 // bool compare_exchange_weak(T& expected, T desired,
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
index e7b9c8ddf654782..cce0fbab1a22ff1 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/ctor.pass.cpp
@@ -8,7 +8,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // constexpr atomic() noexcept;
 // constexpr atomic(floating-point-type) noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
index f076e34bca92b4d..92b0a9d8f8c7923 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 //  T exchange(T, memory_order = memory_order::seq_cst) volatile noexcept;
 //  T exchange(T, memory_order = memory_order::seq_cst) noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index 7734c829326277a..b9b0ae1b530ccf0 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // floating-point-type fetch_add(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
 // floating-point-type fetch_add(floating-point-type,
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index fddd85b0ed5a8af..c2973580f3cc57f 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // floating-point-type fetch_sub(floating-point-type,
 //                               memory_order = memory_order::seq_cst) volatile noexcept;
 // floating-point-type fetch_sub(floating-point-type,
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
index 36535cd49f58baf..02c0567e6506990 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 //  floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept;
 //  floating-point-type load(memory_order = memory_order::seq_cst) noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
index 79b1a517de27d4d..2a0d082e0bc4f5b 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
@@ -8,7 +8,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 //   static constexpr bool is_always_lock_free = implementation-defined;
 //   bool is_lock_free() const volatile noexcept;
 //   bool is_lock_free() const noexcept;
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
index 462c1e429856b67..e26abb9e1a35d77 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 //  void notify_all() volatile noexcept;
 //  void notify_all() noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
index c3a4639698bb09d..7822091392e2ab8 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 //  void notify_one() volatile noexcept;
 //  void notify_one() noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
index 9da7b23cd74c708..aad5f68ee9c9ef3 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.float.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 //  operator floating-point-type() volatile noexcept;
 //  operator floating-point-type() noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index 389d7bdfed106c5..c57a0e0662935a3 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -8,7 +8,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // floating-point-type operator-=(floating-point-type) volatile noexcept;
 // floating-point-type operator-=(floating-point-type) noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index bdafae759fc9f9d..cc3c5f655c8f85f 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -8,7 +8,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // floating-point-type operator+=(floating-point-type) volatile noexcept;
 // floating-point-type operator+=(floating-point-type) noexcept;
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
index 7957e7965ee5c66..32f2caf06b3e923 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
@@ -9,7 +9,6 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 // ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
 
-
 // void store(floating-point-type, memory_order = memory_order::seq_cst) volatile noexcept;
 // void store(floating-point-type, memory_order = memory_order::seq_cst) noexcept;
 

>From 21057f502801a1930c6dba8228205134aac114f3 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sat, 14 Oct 2023 16:29:06 +0100
Subject: [PATCH 13/18] gcc warning

---
 .../atomics.types.generic/atomics.types.float/assign.pass.cpp | 2 +-
 .../atomics.types.float/compare_exchange_strong.pass.cpp      | 4 ++--
 .../atomics.types.float/compare_exchange_weak.pass.cpp        | 4 ++--
 .../atomics.types.float/exchange.pass.cpp                     | 2 +-
 .../atomics.types.float/fetch_add.pass.cpp                    | 2 +-
 .../atomics.types.float/fetch_sub.pass.cpp                    | 2 +-
 .../atomics.types.generic/atomics.types.float/load.pass.cpp   | 2 +-
 .../atomics.types.float/lockfree.pass.cpp                     | 4 ++--
 .../atomics.types.float/notify_all.pass.cpp                   | 2 +-
 .../atomics.types.float/notify_one.pass.cpp                   | 2 +-
 10 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
index b92d87beb06ca32..27c125e9df346b9 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/assign.pass.cpp
@@ -21,7 +21,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileAssign = requires(volatile std::atomic<T> a, T t) { a = t; };
+concept HasVolatileAssign = requires(volatile std::atomic<T>& a, T t) { a = t; };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
index 6b3103c25bdd452..7839c617ad86001 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_strong.pass.cpp
@@ -28,10 +28,10 @@
 
 template <class T, class... Args>
 concept HasVolatileCompareExchangeStrong =
-    requires(volatile std::atomic<T> a, T t, Args... args) { a.compare_exchange_strong(t, t, args...); };
+    requires(volatile std::atomic<T>& a, T t, Args... args) { a.compare_exchange_strong(t, t, args...); };
 
 template <class T, template <class> class MaybeVolatile, class... Args>
-concept HasNoexceptCompareExchangeStrong = requires(MaybeVolatile<std::atomic<T>> a, T t, Args... args) {
+concept HasNoexceptCompareExchangeStrong = requires(MaybeVolatile<std::atomic<T>>& a, T t, Args... args) {
   { a.compare_exchange_strong(t, t, args...) } noexcept;
 };
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
index c5bff48480feb70..3e5b20c799a88f9 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/compare_exchange_weak.pass.cpp
@@ -28,10 +28,10 @@
 
 template <class T, class... Args>
 concept HasVolatileCompareExchangeWeak =
-    requires(volatile std::atomic<T> a, T t, Args... args) { a.compare_exchange_weak(t, t, args...); };
+    requires(volatile std::atomic<T>& a, T t, Args... args) { a.compare_exchange_weak(t, t, args...); };
 
 template <class T, template <class> class MaybeVolatile, class... Args>
-concept HasNoexceptCompareExchangeWeak = requires(MaybeVolatile<std::atomic<T>> a, T t, Args... args) {
+concept HasNoexceptCompareExchangeWeak = requires(MaybeVolatile<std::atomic<T>>& a, T t, Args... args) {
   { a.compare_exchange_weak(t, t, args...) } noexcept;
 };
 
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
index 92b0a9d8f8c7923..8e25ede6ae86135 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/exchange.pass.cpp
@@ -21,7 +21,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileExchange = requires(volatile std::atomic<T> a, T t) { a.exchange(t); };
+concept HasVolatileExchange = requires(volatile std::atomic<T>& a, T t) { a.exchange(t); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
index b9b0ae1b530ccf0..778966648311eb0 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add.pass.cpp
@@ -25,7 +25,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileFetchAdd = requires(volatile std::atomic<T> a, T t) { a.fetch_add(t); };
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
index c2973580f3cc57f..34b631b46c2d1db 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_sub.pass.cpp
@@ -25,7 +25,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileFetchSub = requires(volatile std::atomic<T> a, T t) { a.fetch_sub(t); };
+concept HasVolatileFetchSub = requires(volatile std::atomic<T>& a, T t) { a.fetch_sub(t); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
index 02c0567e6506990..fbd1aae9d8824cc 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp
@@ -25,7 +25,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileLoad = requires(volatile std::atomic<T> a, T t) { a.load(); };
+concept HasVolatileLoad = requires(volatile std::atomic<T>& a, T t) { a.load(); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
index 2a0d082e0bc4f5b..90d10f7725b756d 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/lockfree.pass.cpp
@@ -26,8 +26,8 @@ concept isLockFreeNoexcept = requires(T t) {
 
 template <class T>
 void test() {
-  static_assert(isLockFreeNoexcept<const std::atomic<T>>);
-  static_assert(isLockFreeNoexcept<const volatile std::atomic<T>>);
+  static_assert(isLockFreeNoexcept<const std::atomic<T>&>);
+  static_assert(isLockFreeNoexcept<const volatile std::atomic<T>&>);
 
   //   static constexpr bool is_always_lock_free = implementation-defined;
   { [[maybe_unused]] constexpr std::same_as<const bool> decltype(auto) r = std::atomic<T>::is_always_lock_free; }
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
index e26abb9e1a35d77..16af57f72fc21fe 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_all.pass.cpp
@@ -23,7 +23,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileNotifyAll = requires(volatile std::atomic<T> a, T t) { a.notify_all(); };
+concept HasVolatileNotifyAll = requires(volatile std::atomic<T>& a, T t) { a.notify_all(); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
index 7822091392e2ab8..377d707b63f9953 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/notify_one.pass.cpp
@@ -23,7 +23,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileNotifyOne = requires(volatile std::atomic<T> a, T t) { a.notify_one(); };
+concept HasVolatileNotifyOne = requires(volatile std::atomic<T>& a, T t) { a.notify_one(); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {

>From 3852e7a2af729caa50eda5317ff93d40812a1730 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sat, 14 Oct 2023 16:48:57 +0100
Subject: [PATCH 14/18] relax floating point comparison

---
 .../atomics.types.float/test_helper.h         | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
index 5ccb9cb86a1803e..98573fc9c48931e 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/test_helper.h
@@ -11,9 +11,16 @@
 
 #include <atomic>
 #include <cassert>
+#include <cmath>
 #include <thread>
 #include <vector>
 
+template <class T>
+bool approximately_equals(T x, T y) {
+  T epsilon = 0.001;
+  return std::abs(x - y) < epsilon;
+}
+
 // Test that all threads see the exact same sequence of events
 // Test will pass 100% if store_op and load_op are correctly
 // affecting the memory with seq_cst order
@@ -34,19 +41,19 @@ void test_seq_cst(StoreOp store_op, LoadOp load_op) {
     std::thread t2([&] { store_op(y, old_value, new_value); });
 
     std::thread t3([&] {
-      while (load_op(x) != new_value) {
+      while (!approximately_equals(load_op(x), new_value)) {
         std::this_thread::yield();
       }
-      if (load_op(y) != new_value) {
+      if (!approximately_equals(load_op(y), new_value)) {
         x_update_first.store(true, std::memory_order_relaxed);
       }
     });
 
     std::thread t4([&] {
-      while (load_op(y) != new_value) {
+      while (!approximately_equals(load_op(y), new_value)) {
         std::this_thread::yield();
       }
-      if (load_op(x) != new_value) {
+      if (!approximately_equals(load_op(x), new_value)) {
         y_update_first.store(true, std::memory_order_relaxed);
       }
     });
@@ -55,6 +62,7 @@ void test_seq_cst(StoreOp store_op, LoadOp load_op) {
     t2.join();
     t3.join();
     t4.join();
+    // thread 3 and thread 4 cannot see different orders of storing x and y
     assert(!(x_update_first && y_update_first));
   }
 }
@@ -77,9 +85,11 @@ void test_acquire_release(StoreOp store_op, LoadOp load_op) {
 
     for (auto j = 0; j < number_of_threads; ++j) {
       threads.emplace_back([&at, &non_atomic, load_op, new_value] {
-        while (load_op(at) != new_value) {
+        while (!approximately_equals(load_op(at), new_value)) {
           std::this_thread::yield();
         }
+        // Other thread's writes before the release store are visible
+        // in this thread's read after the acquire load
         assert(non_atomic == 6);
       });
     }

>From aa87ec4c154ad470b8e0722c1117d3c66c48e8e3 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sat, 14 Oct 2023 19:45:48 +0100
Subject: [PATCH 15/18] test which test hangs in CI

---
 .../atomics.types.float/fetch_add1.pass.cpp   | 58 +++++++++++++
 .../atomics.types.float/fetch_add2.pass.cpp   | 82 +++++++++++++++++++
 .../atomics.types.float/fetch_add3.pass.cpp   | 58 +++++++++++++
 .../atomics.types.float/fetch_add4.pass.cpp   | 60 ++++++++++++++
 .../operator.minus_equals.pass.cpp            |  2 +-
 .../operator.plus_equals.pass.cpp             |  2 +-
 .../atomics.types.float/store.pass.cpp        |  2 +-
 .../atomics.types.float/wait.pass.cpp         |  2 +-
 8 files changed, 262 insertions(+), 4 deletions(-)
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add2.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add3.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add4.pass.cpp

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1.pass.cpp
new file mode 100644
index 000000000000000..dfbbcdc44c5ba68
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
+
+  // fetch_add
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2), std::memory_order::relaxed);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add2.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add2.pass.cpp
new file mode 100644
index 000000000000000..5774acf7c0da0e8
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add2.pass.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
+
+  // fetch_add concurrent
+  {
+    constexpr auto number_of_threads = 4;
+    constexpr auto loop              = 1000;
+
+    MaybeVolatile<std::atomic<T>> at;
+
+    std::vector<std::thread> threads;
+    threads.reserve(number_of_threads);
+    for (auto i = 0; i < number_of_threads; ++i) {
+      threads.emplace_back([&at]() {
+        for (auto j = 0; j < loop; ++j) {
+          at.fetch_add(T(1.234), std::memory_order::relaxed);
+        }
+      });
+    }
+
+    for (auto& thread : threads) {
+      thread.join();
+    }
+
+    const auto times = [](T t, int n) {
+      T res(0);
+      for (auto i = 0; i < n; ++i) {
+        res += t;
+      }
+      return res;
+    };
+
+    assert(at.load() == times(1.234, number_of_threads * loop));
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add3.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add3.pass.cpp
new file mode 100644
index 000000000000000..00322137d918528
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add3.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
+  // memory_order::release
+  {
+    auto store = [](MaybeVolatile<std::atomic<T>>& x, T old_val, T new_val) {
+      x.fetch_add(new_val - old_val, std::memory_order::release);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
+    test_acquire_release<T, MaybeVolatile>(store, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add4.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add4.pass.cpp
new file mode 100644
index 000000000000000..17ccb0e99aab7e2
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add4.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
+  // memory_order::seq_cst
+  {
+    auto fetch_add = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) { x.fetch_add(new_val - old_value); };
+    auto fetch_add_with_order = [](MaybeVolatile<std::atomic<T>>& x, T old_value, T new_val) {
+      x.fetch_add(new_val - old_value, std::memory_order::seq_cst);
+    };
+    auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
+    test_seq_cst<T, MaybeVolatile>(fetch_add, load);
+    test_seq_cst<T, MaybeVolatile>(fetch_add_with_order, load);
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
index c57a0e0662935a3..687bb9bfb97a11e 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.minus_equals.pass.cpp
@@ -22,7 +22,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileMinusEquals = requires(volatile std::atomic<T> a, T t) { a -= t; };
+concept HasVolatileMinusEquals = requires(volatile std::atomic<T>& a, T t) { a -= t; };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
index cc3c5f655c8f85f..51dda0e7fc40382 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/operator.plus_equals.pass.cpp
@@ -22,7 +22,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatilePlusEquals = requires(volatile std::atomic<T> a, T t) { a += t; };
+concept HasVolatilePlusEquals = requires(volatile std::atomic<T>& a, T t) { a += t; };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
index 32f2caf06b3e923..e39311cb6d43851 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/store.pass.cpp
@@ -25,7 +25,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileStore = requires(volatile std::atomic<T> a, T t) { a.store(t); };
+concept HasVolatileStore = requires(volatile std::atomic<T>& a, T t) { a.store(t); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
index 2b4eda520178741..5d82a4e27f13a0a 100644
--- a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/wait.pass.cpp
@@ -24,7 +24,7 @@
 #include "test_macros.h"
 
 template <class T>
-concept HasVolatileWait = requires(volatile std::atomic<T> a, T t) { a.wait(T()); };
+concept HasVolatileWait = requires(volatile std::atomic<T>& a, T t) { a.wait(T()); };
 
 template <class T, template <class> class MaybeVolatile = std::type_identity_t>
 void testImpl() {

>From 8bddedb721cc09f81311d0bc9ed707866f90d17c Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sat, 14 Oct 2023 23:29:14 +0100
Subject: [PATCH 16/18] try to figure out which one

---
 .../fetch_add1_double.pass.cpp                | 56 +++++++++++++++++++
 .../fetch_add1_float.pass.cpp                 | 56 +++++++++++++++++++
 .../fetch_add1_long_double.pass.cpp           | 56 +++++++++++++++++++
 3 files changed, 168 insertions(+)
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_double.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_float.pass.cpp
 create mode 100644 libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_long_double.pass.cpp

diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_double.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_double.pass.cpp
new file mode 100644
index 000000000000000..7e26abe9766e600
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_double.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
+
+  // fetch_add
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2), std::memory_order::relaxed);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<double>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_float.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_float.pass.cpp
new file mode 100644
index 000000000000000..c782f476a1c036e
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_float.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
+
+  // fetch_add
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2), std::memory_order::relaxed);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<float>();
+
+  return 0;
+}
diff --git a/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_long_double.pass.cpp b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_long_double.pass.cpp
new file mode 100644
index 000000000000000..8f3f275593a0e1e
--- /dev/null
+++ b/libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/fetch_add1_long_double.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// ADDITIONAL_COMPILE_FLAGS(has-latomic): -latomic
+
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) volatile noexcept;
+// floating-point-type fetch_add(floating-point-type,
+//                               memory_order = memory_order::seq_cst) noexcept;
+
+#include <atomic>
+#include <cassert>
+#include <concepts>
+#include <thread>
+#include <type_traits>
+#include <vector>
+
+#include "test_helper.h"
+#include "test_macros.h"
+
+template <class T>
+concept HasVolatileFetchAdd = requires(volatile std::atomic<T>& a, T t) { a.fetch_add(t); };
+
+template <class T, template <class> class MaybeVolatile = std::type_identity_t>
+void testImpl() {
+  static_assert(HasVolatileFetchAdd<T> == std::atomic<T>::is_always_lock_free);
+  static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().fetch_add(T(0))));
+
+  // fetch_add
+  {
+    MaybeVolatile<std::atomic<T>> a(3.1);
+    std::same_as<T> decltype(auto) r = a.fetch_add(T(1.2), std::memory_order::relaxed);
+    assert(r == T(3.1));
+    assert(a.load() == T(3.1) + T(1.2));
+  }
+}
+
+template <class T>
+void test() {
+  testImpl<T>();
+  if constexpr (std::atomic<T>::is_always_lock_free) {
+    testImpl<T, std::add_volatile_t>();
+  }
+}
+
+int main(int, char**) {
+  test<long double>();
+
+  return 0;
+}

>From f3a54cd32efe0eb54cd4e8633164ac183156be3a Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sun, 15 Oct 2023 09:10:19 +0100
Subject: [PATCH 17/18] using compare_exchange_strong for long double

---
 libcxx/include/__atomic/atomic.h | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index 1cc91c44458b30d..3a9b53ccaacb235 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -145,8 +145,8 @@ template <class _Tp>
   requires is_floating_point_v<_Tp>
 struct atomic<_Tp> : public __atomic_base<_Tp> {
   private:
-    // The builtin __cxx_atomic_fetch_add does not work for
-    // long double on some platforms with fp80 type
+    // The builtin __cxx_atomic_fetch_add errors during compilation for
+    // long double on some platforms with fp80 type.
     // There is no way on the libc++ side to test whether it is
     // ok to use the builtin for a certain type.
     // Therefore, we do not use the builtin here
@@ -164,13 +164,17 @@ struct atomic<_Tp> : public __atomic_base<_Tp> {
     _LIBCPP_HIDE_FROM_ABI static _Tp __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _Operation __operation) {
         _Tp __old = __self.load(memory_order_relaxed);
         _Tp __new = __operation(__old, __operand);
-        while (!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
-          if constexpr (std::is_same_v<_Tp, long double>) {
-            // https://github.com/llvm/llvm-project/issues/47978
-            // clang bug: __old is not updated on failure for atomic<long double>
-            __old = __self.load(memory_order_relaxed);
+
+        if constexpr (std::is_same_v<_Tp, long double>) {
+          // https://github.com/llvm/llvm-project/issues/47978
+          // clang bug: __old is not updated on failure for atomic<long double>::compare_exchange_strong
+          while (!__self.compare_exchange_strong(__old, __new, __m, memory_order_relaxed)) {
+            __new = __operation(__old, __operand);
+          }
+        } else {
+          while (!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) {
+            __new = __operation(__old, __operand);
           }
-          __new = __operation(__old, __operand);
         }
         return __old;
     }

>From 57824e217b97d773197b1c08c4811bcc2c12e2a3 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sun, 15 Oct 2023 14:00:53 +0100
Subject: [PATCH 18/18] try again

---
 libcxx/include/__atomic/atomic.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h
index 3a9b53ccaacb235..547c63c44ee5525 100644
--- a/libcxx/include/__atomic/atomic.h
+++ b/libcxx/include/__atomic/atomic.h
@@ -166,9 +166,10 @@ struct atomic<_Tp> : public __atomic_base<_Tp> {
         _Tp __new = __operation(__old, __operand);
 
         if constexpr (std::is_same_v<_Tp, long double>) {
-          // https://github.com/llvm/llvm-project/issues/47978
-          // clang bug: __old is not updated on failure for atomic<long double>::compare_exchange_strong
           while (!__self.compare_exchange_strong(__old, __new, __m, memory_order_relaxed)) {
+            // https://github.com/llvm/llvm-project/issues/47978
+            // clang bug: __old is not updated on failure for atomic<long double>::compare_exchange_strong
+            __old = __self.load(memory_order_relaxed);
             __new = __operation(__old, __operand);
           }
         } else {



More information about the libcxx-commits mailing list