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

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