alpaka
Abstraction Library for Parallel Kernel Acceleration
AtomicAtomicRef.hpp
Go to the documentation of this file.
1 /* Copyright 2022 Felice Pantaleo, Andrea Bocci, Jan Stephan
2  * SPDX-License-Identifier: MPL-2.0
3  */
4 
5 #pragma once
6 
9 
10 #include <array>
11 #include <atomic>
12 #include <type_traits>
13 
14 #ifndef ALPAKA_DISABLE_ATOMIC_ATOMICREF
15 # ifndef ALPAKA_HAS_STD_ATOMIC_REF
16 # include <boost/atomic.hpp>
17 # endif
18 
19 namespace alpaka
20 {
21  namespace detail
22  {
23 # if defined(ALPAKA_HAS_STD_ATOMIC_REF)
24  template<typename T>
25  using atomic_ref = std::atomic_ref<T>;
26 # else
27  template<typename T>
28  using atomic_ref = boost::atomic_ref<T>;
29 # endif
30  } // namespace detail
31 
32  //! The atomic ops based on atomic_ref for CPU accelerators.
33  //
34  // Atomics can be used in the grids, blocks and threads hierarchy levels.
35  //
36 
38  {
39  };
40 
41  template<typename T>
43  {
44  static_assert(
45  std::is_trivially_copyable_v<T> && detail::atomic_ref<T>::required_alignment <= alignof(T),
46  "Type not supported by AtomicAtomicRef, please recompile defining "
47  "ALPAKA_DISABLE_ATOMIC_ATOMICREF.");
48  }
49 
50  namespace trait
51  {
52  //! The CPU accelerators AtomicAdd.
53  template<typename T, typename THierarchy>
54  struct AtomicOp<AtomicAdd, AtomicAtomicRef, T, THierarchy>
55  {
56  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
57  {
58  isSupportedByAtomicAtomicRef<T>();
59  detail::atomic_ref<T> ref(*addr);
60  return ref.fetch_add(value);
61  }
62  };
63 
64  //! The CPU accelerators AtomicSub.
65  template<typename T, typename THierarchy>
66  struct AtomicOp<AtomicSub, AtomicAtomicRef, T, THierarchy>
67  {
68  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
69  {
70  isSupportedByAtomicAtomicRef<T>();
71  detail::atomic_ref<T> ref(*addr);
72  return ref.fetch_sub(value);
73  }
74  };
75 
76  //! The CPU accelerators AtomicMin.
77  template<typename T, typename THierarchy>
78  struct AtomicOp<AtomicMin, AtomicAtomicRef, T, THierarchy>
79  {
80  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
81  {
82  isSupportedByAtomicAtomicRef<T>();
83  detail::atomic_ref<T> ref(*addr);
84  T old = ref;
85  T result = old;
86  result = std::min(result, value);
87  while(!ref.compare_exchange_weak(old, result))
88  {
89  result = old;
90  result = std::min(result, value);
91  }
92  return old;
93  }
94  };
95 
96  //! The CPU accelerators AtomicMax.
97  template<typename T, typename THierarchy>
98  struct AtomicOp<AtomicMax, AtomicAtomicRef, T, THierarchy>
99  {
100  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
101  {
102  isSupportedByAtomicAtomicRef<T>();
103  detail::atomic_ref<T> ref(*addr);
104  T old = ref;
105  T result = old;
106  result = std::max(result, value);
107  while(!ref.compare_exchange_weak(old, result))
108  {
109  result = old;
110  result = std::max(result, value);
111  }
112  return old;
113  }
114  };
115 
116  //! The CPU accelerators AtomicExch.
117  template<typename T, typename THierarchy>
118  struct AtomicOp<AtomicExch, AtomicAtomicRef, T, THierarchy>
119  {
120  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
121  {
122  isSupportedByAtomicAtomicRef<T>();
123  detail::atomic_ref<T> ref(*addr);
124  T old = ref;
125  T result = value;
126  while(!ref.compare_exchange_weak(old, result))
127  {
128  result = value;
129  }
130  return old;
131  }
132  };
133 
134  //! The CPU accelerators AtomicInc.
135  template<typename T, typename THierarchy>
136  struct AtomicOp<AtomicInc, AtomicAtomicRef, T, THierarchy>
137  {
138  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
139  {
140  isSupportedByAtomicAtomicRef<T>();
141  detail::atomic_ref<T> ref(*addr);
142  T old = ref;
143  T result = ((old >= value) ? 0 : static_cast<T>(old + 1));
144  while(!ref.compare_exchange_weak(old, result))
145  {
146  result = ((old >= value) ? 0 : static_cast<T>(old + 1));
147  }
148  return old;
149  }
150  };
151 
152  //! The CPU accelerators AtomicDec.
153  template<typename T, typename THierarchy>
154  struct AtomicOp<AtomicDec, AtomicAtomicRef, T, THierarchy>
155  {
156  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
157  {
158  isSupportedByAtomicAtomicRef<T>();
159  detail::atomic_ref<T> ref(*addr);
160  T old = ref;
161  T result = ((old >= value) ? 0 : static_cast<T>(old - 1));
162  while(!ref.compare_exchange_weak(old, result))
163  {
164  result = ((old >= value) ? 0 : static_cast<T>(old - 1));
165  }
166  return old;
167  }
168  };
169 
170  //! The CPU accelerators AtomicAnd.
171  template<typename T, typename THierarchy>
172  struct AtomicOp<AtomicAnd, AtomicAtomicRef, T, THierarchy>
173  {
174  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
175  {
176  isSupportedByAtomicAtomicRef<T>();
177  detail::atomic_ref<T> ref(*addr);
178  return ref.fetch_and(value);
179  }
180  };
181 
182  //! The CPU accelerators AtomicOr.
183  template<typename T, typename THierarchy>
184  struct AtomicOp<AtomicOr, AtomicAtomicRef, T, THierarchy>
185  {
186  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
187  {
188  isSupportedByAtomicAtomicRef<T>();
189  detail::atomic_ref<T> ref(*addr);
190  return ref.fetch_or(value);
191  }
192  };
193 
194  //! The CPU accelerators AtomicXor.
195  template<typename T, typename THierarchy>
196  struct AtomicOp<AtomicXor, AtomicAtomicRef, T, THierarchy>
197  {
198  ALPAKA_FN_HOST static auto atomicOp(AtomicAtomicRef const&, T* const addr, T const& value) -> T
199  {
200  isSupportedByAtomicAtomicRef<T>();
201  detail::atomic_ref<T> ref(*addr);
202  return ref.fetch_xor(value);
203  }
204  };
205 
206  //! The CPU accelerators AtomicCas.
207  template<typename T, typename THierarchy>
208  struct AtomicOp<AtomicCas, AtomicAtomicRef, T, THierarchy>
209  {
211  AtomicAtomicRef const&,
212  T* const addr,
213  T const& compare,
214  T const& value) -> T
215  {
216  isSupportedByAtomicAtomicRef<T>();
217  detail::atomic_ref<T> ref(*addr);
218  T old = ref;
219  T result;
220  do
221  {
222  result = ((old == compare) ? value : old);
223  } while(!ref.compare_exchange_weak(old, result));
224  return old;
225  }
226  };
227  } // namespace trait
228 } // namespace alpaka
229 
230 #endif
The atomic ops based on atomic_ref for CPU accelerators.
#define ALPAKA_FN_HOST
Definition: Common.hpp:40
boost::atomic_ref< T > atomic_ref
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto max(T const &max_ctx, Tx const &x, Ty const &y)
Returns the larger of two arguments. NaNs are treated as missing data (between a NaN and a numeric va...
Definition: Traits.hpp:1263
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto min(T const &min_ctx, Tx const &x, Ty const &y)
Returns the smaller of two arguments. NaNs are treated as missing data (between a NaN and a numeric v...
Definition: Traits.hpp:1280
The alpaka accelerator library.
void isSupportedByAtomicAtomicRef()
The addition function object.
Definition: Op.hpp:17
The and function object.
Definition: Op.hpp:140
The compare and swap function object.
Definition: Op.hpp:185
The decrement function object.
Definition: Op.hpp:123
The exchange function object.
Definition: Op.hpp:91
The increment function object.
Definition: Op.hpp:106
The maximum function object.
Definition: Op.hpp:76
The minimum function object.
Definition: Op.hpp:61
The or function object.
Definition: Op.hpp:155
The subtraction function object.
Definition: Op.hpp:39
The exclusive or function object.
Definition: Op.hpp:170
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &compare, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicAtomicRef const &, T *const addr, T const &value) -> T
The atomic operation trait.
Definition: Traits.hpp:60