1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// UNSUPPORTED: c++03, c++11, c++14, c++17
9// XFAIL: !has-64-bit-atomics
10
11// floating-point-type load(memory_order = memory_order::seq_cst) volatile noexcept;
12// floating-point-type load(memory_order = memory_order::seq_cst) noexcept;
13
14#include <atomic>
15#include <algorithm>
16#include <cassert>
17#include <concepts>
18#include <memory>
19#include <ranges>
20#include <type_traits>
21#include <vector>
22
23#include "test_helper.h"
24#include "test_macros.h"
25
26#ifndef TEST_HAS_NO_THREADS
27# include "make_test_thread.h"
28# include <thread>
29#endif
30
31template <class T>
32concept HasVolatileLoad = requires(volatile std::atomic<T>& a, T t) { a.load(); };
33
34template <class T, template <class> class MaybeVolatile = std::type_identity_t>
35void test_impl() {
36 // Uncomment the test after P1831R1 is implemented
37 // static_assert(HasVolatileLoad<T> == std::atomic<T>::is_always_lock_free);
38 static_assert(noexcept(std::declval<MaybeVolatile<std::atomic<T>>&>().load()));
39
40 // load
41 {
42 MaybeVolatile<std::atomic<T>> a(T(3.1));
43 a.store(T(1.2));
44 std::same_as<T> decltype(auto) r = a.load(std::memory_order::relaxed);
45 assert(r == T(1.2));
46 }
47
48#ifndef TEST_HAS_NO_THREADS
49 // memory_order::relaxed
50 {
51 constexpr auto number_of_threads = 4;
52 constexpr auto loop = 1000;
53
54 MaybeVolatile<std::atomic<T>> at(T(-1.0));
55
56 std::vector<std::thread> threads;
57 threads.reserve(n: number_of_threads);
58 for (auto i = 0; i < number_of_threads; ++i) {
59 threads.push_back(support::make_test_thread([&at, i]() {
60 for (auto j = 0; j < loop; ++j) {
61 at.store(T(i));
62 }
63 }));
64 }
65
66 while (at.load(std::memory_order::relaxed) == T(-1.0)) {
67 std::this_thread::yield();
68 }
69
70 for (auto i = 0; i < loop; ++i) {
71 auto r = at.load(std::memory_order_relaxed);
72 assert(std::ranges::any_of(std::views::iota(0, number_of_threads), [r](auto j) { return r == T(j); }));
73 }
74
75 for (auto& thread : threads) {
76 thread.join();
77 }
78 }
79
80 // memory_order::consume
81 {
82 std::unique_ptr<T> p = std::make_unique<T>(T(0.0));
83 MaybeVolatile<std::atomic<T>> at(T(0.0));
84
85 constexpr auto number_of_threads = 8;
86 std::vector<std::thread> threads;
87 threads.reserve(n: number_of_threads);
88
89 for (auto i = 0; i < number_of_threads; ++i) {
90 threads.push_back(support::make_test_thread([&at, &p] {
91 while (at.load(std::memory_order::consume) == T(0.0)) {
92 std::this_thread::yield();
93 }
94 assert(*p == T(1.0)); // the write from other thread should be visible
95 }));
96 }
97
98 *p = T(1.0);
99 at.store(*p, std::memory_order_release);
100
101 for (auto& thread : threads) {
102 thread.join();
103 }
104 }
105#endif
106
107 // memory_order::acquire
108 {
109 auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val, std::memory_order::release); };
110 auto load = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::acquire); };
111 test_acquire_release<T, MaybeVolatile>(store, load);
112 }
113
114 // memory_order::seq_cst
115 {
116 auto store = [](MaybeVolatile<std::atomic<T>>& x, T, T new_val) { x.store(new_val); };
117 auto load_no_arg = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(); };
118 auto load_with_order = [](MaybeVolatile<std::atomic<T>>& x) { return x.load(std::memory_order::seq_cst); };
119 test_seq_cst<T, MaybeVolatile>(store, load_no_arg);
120 test_seq_cst<T, MaybeVolatile>(store, load_with_order);
121 }
122}
123
124template <class T>
125void test() {
126 test_impl<T>();
127 if constexpr (std::atomic<T>::is_always_lock_free) {
128 test_impl<T, std::add_volatile_t>();
129 }
130}
131
132int main(int, char**) {
133 test<float>();
134 test<double>();
135 // TODO https://github.com/llvm/llvm-project/issues/47978
136 // test<long double>();
137
138 return 0;
139}
140

source code of libcxx/test/std/atomics/atomics.types.generic/atomics.types.float/load.pass.cpp