alpaka
Abstraction Library for Parallel Kernel Acceleration
AtomicOmpBuiltIn.hpp
Go to the documentation of this file.
1 /* Copyright 2022 RenĂ© Widera, Bernhard Manfred Gruber
2  * SPDX-License-Identifier: MPL-2.0
3  */
4 
5 #pragma once
6 
7 #include "alpaka/atomic/Op.hpp"
10 
11 #ifdef _OPENMP
12 
13 namespace alpaka
14 {
15  //! The OpenMP accelerators atomic ops.
16  //
17  // Atomics can be used in the blocks and threads hierarchy levels.
18  // Atomics are not guaranteed to be safe between devices or grids.
20  {
21  };
22 
23  namespace trait
24  {
25 // check for OpenMP 3.1+
26 // "omp atomic capture" is not supported before OpenMP 3.1
27 # if _OPENMP >= 201107
28 
29  //! The OpenMP accelerators atomic operation: ADD
30  template<typename T, typename THierarchy>
31  struct AtomicOp<AtomicAdd, AtomicOmpBuiltIn, T, THierarchy>
32  {
33  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
34  {
35  T old;
36  auto& ref(*addr);
37 // atomically update ref, but capture the original value in old
38 # if BOOST_COMP_GNUC
39 # pragma GCC diagnostic push
40 # pragma GCC diagnostic ignored "-Wconversion"
41 # endif
42 # pragma omp atomic capture
43  {
44  old = ref;
45  ref += value;
46  }
47 # if BOOST_COMP_GNUC
48 # pragma GCC diagnostic pop
49 # endif
50  return old;
51  }
52  };
53 
54  //! The OpenMP accelerators atomic operation: SUB
55  template<typename T, typename THierarchy>
56  struct AtomicOp<AtomicSub, AtomicOmpBuiltIn, T, THierarchy>
57  {
58  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
59  {
60  T old;
61  auto& ref(*addr);
62 // atomically update ref, but capture the original value in old
63 # if BOOST_COMP_GNUC
64 # pragma GCC diagnostic push
65 # pragma GCC diagnostic ignored "-Wconversion"
66 # endif
67 # pragma omp atomic capture
68  {
69  old = ref;
70  ref -= value;
71  }
72 # if BOOST_COMP_GNUC
73 # pragma GCC diagnostic pop
74 # endif
75  return old;
76  }
77  };
78 
79  //! The OpenMP accelerators atomic operation: EXCH
80  template<typename T, typename THierarchy>
81  struct AtomicOp<AtomicExch, AtomicOmpBuiltIn, T, THierarchy>
82  {
83  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
84  {
85  T old;
86  auto& ref(*addr);
87 // atomically update ref, but capture the original value in old
88 # pragma omp atomic capture
89  {
90  old = ref;
91  ref = value;
92  }
93  return old;
94  }
95  };
96 
97  //! The OpenMP accelerators atomic operation: AND
98  template<typename T, typename THierarchy>
99  struct AtomicOp<AtomicAnd, AtomicOmpBuiltIn, T, THierarchy>
100  {
101  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
102  {
103  T old;
104  auto& ref(*addr);
105 // atomically update ref, but capture the original value in old
106 # if BOOST_COMP_GNUC
107 # pragma GCC diagnostic push
108 # pragma GCC diagnostic ignored "-Wconversion"
109 # endif
110 # pragma omp atomic capture
111  {
112  old = ref;
113  ref &= value;
114  }
115 # if BOOST_COMP_GNUC
116 # pragma GCC diagnostic pop
117 # endif
118  return old;
119  }
120  };
121 
122  //! The OpenMP accelerators atomic operation: OR
123  template<typename T, typename THierarchy>
124  struct AtomicOp<AtomicOr, AtomicOmpBuiltIn, T, THierarchy>
125  {
126  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
127  {
128  T old;
129  auto& ref(*addr);
130 // atomically update ref, but capture the original value in old
131 # if BOOST_COMP_GNUC
132 # pragma GCC diagnostic push
133 # pragma GCC diagnostic ignored "-Wconversion"
134 # endif
135 # pragma omp atomic capture
136  {
137  old = ref;
138  ref |= value;
139  }
140 # if BOOST_COMP_GNUC
141 # pragma GCC diagnostic pop
142 # endif
143  return old;
144  }
145  };
146 
147  //! The OpenMP accelerators atomic operation: XOR
148  template<typename T, typename THierarchy>
149  struct AtomicOp<AtomicXor, AtomicOmpBuiltIn, T, THierarchy>
150  {
151  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
152  {
153  T old;
154  auto& ref(*addr);
155 // atomically update ref, but capture the original value in old
156 # if BOOST_COMP_GNUC
157 # pragma GCC diagnostic push
158 # pragma GCC diagnostic ignored "-Wconversion"
159 # endif
160 # pragma omp atomic capture
161  {
162  old = ref;
163  ref ^= value;
164  }
165 # if BOOST_COMP_GNUC
166 # pragma GCC diagnostic pop
167 # endif
168  return old;
169  }
170  };
171 
172 # endif // _OPENMP >= 201107
173 
174 // check for OpenMP 5.1+
175 // "omp atomic compare" was introduced with OpenMP 5.1
176 # if _OPENMP >= 202011
177 
178  //! The OpenMP accelerators atomic operation: Min
179  template<typename T, typename THierarchy>
180  struct AtomicOp<AtomicMin, AtomicOmpBuiltIn, T, THierarchy>
181  {
182  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T value) -> T
183  {
184  T old;
185  auto& ref(*addr);
186 // atomically update ref, but capture the original value in old
187 # pragma omp atomic capture compare
188  {
189  old = ref;
190  // Do not remove the curly brackets of the if body else
191  // icpx 2024.0 is not able to compile the atomics.
192  if(value < ref)
193  {
194  ref = value;
195  }
196  }
197  return old;
198  }
199  };
200 
201  //! The OpenMP accelerators atomic operation: Max
202  template<typename T, typename THierarchy>
203  struct AtomicOp<AtomicMax, AtomicOmpBuiltIn, T, THierarchy>
204  {
205  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T value) -> T
206  {
207  T old;
208  auto& ref(*addr);
209 // atomically update ref, but capture the original value in old
210 # pragma omp atomic capture compare
211  {
212  old = ref;
213  // Do not remove the curly brackets of the if body else
214  // icpx 2024.0 is not able to compile the atomics.
215  if(value > ref)
216  {
217  ref = value;
218  }
219  }
220  return old;
221  }
222  };
223 
224  //! The OpenMP accelerators atomic operation: Inc
225  template<typename T, typename THierarchy>
226  struct AtomicOp<AtomicInc, AtomicOmpBuiltIn, T, THierarchy>
227  {
228  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
229  {
230  // TODO(bgruber): atomic increment with wrap around is not implementable in OpenMP 5.1
231  T old;
232 # pragma omp critical(AlpakaOmpAtomicOp)
233  {
234  old = AtomicInc{}(addr, value);
235  }
236  return old;
237  }
238  };
239 
240  //! The OpenMP accelerators atomic operation: Dec
241  template<typename T, typename THierarchy>
242  struct AtomicOp<AtomicDec, AtomicOmpBuiltIn, T, THierarchy>
243  {
244  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
245  {
246  // TODO(bgruber): atomic decrement with wrap around is not implementable in OpenMP 5.1
247  T old;
248 # pragma omp critical(AlpakaOmpAtomicOp)
249  {
250  old = AtomicDec{}(addr, value);
251  }
252  return old;
253  }
254  };
255 
256  //! The OpenMP accelerators atomic operation: Cas
257  template<typename T, typename THierarchy>
258  struct AtomicOp<AtomicCas, AtomicOmpBuiltIn, T, THierarchy>
259  {
260  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T compare, T value) -> T
261  {
262  T old;
263  auto& ref(*addr);
264 // atomically update ref, but capture the original value in old
265 # pragma omp atomic capture compare
266  {
267  old = ref;
268  // Do not remove the curly brackets of the if body else
269  // icpx 2024.0 is not able to compile the atomics.
270  if(ref == compare)
271  {
272  ref = value;
273  }
274  }
275  return old;
276  }
277  };
278 
279 # else
280  //! The OpenMP accelerators atomic operation
281  //
282  // generic implementations for operations where native atomics are not available
283  template<typename TOp, typename T, typename THierarchy>
284  struct AtomicOp<TOp, AtomicOmpBuiltIn, T, THierarchy>
285  {
286  ALPAKA_FN_HOST static auto atomicOp(AtomicOmpBuiltIn const&, T* const addr, T const& value) -> T
287  {
288  T old;
289  // \TODO: Currently not only the access to the same memory location is protected by a mutex but all
290  // atomic ops on all threads.
291 # pragma omp critical(AlpakaOmpAtomicOp)
292  {
293  old = TOp()(addr, value);
294  }
295  return old;
296  }
297 
299  AtomicOmpBuiltIn const&,
300  T* const addr,
301  T const& compare,
302  T const& value) -> T
303  {
304  T old;
305  // \TODO: Currently not only the access to the same memory location is protected by a mutex but all
306  // atomic ops on all threads.
307 # pragma omp critical(AlpakaOmpAtomicOp2)
308  {
309  old = TOp()(addr, compare, value);
310  }
311  return old;
312  }
313  };
314 
315 # endif // _OPENMP >= 202011
316 
317  } // namespace trait
318 } // namespace alpaka
319 
320 #endif
The OpenMP accelerators atomic ops.
#define ALPAKA_FN_HOST
Definition: Common.hpp:40
The alpaka accelerator library.
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto atomicOp(TAtomic const &atomic, T *const addr, T const &value, THierarchy const &=THierarchy()) -> T
Executes the given operation atomically.
Definition: Traits.hpp:73
The addition function object.
Definition: Op.hpp:17
The and function object.
Definition: Op.hpp:140
The exchange function object.
Definition: Op.hpp:91
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(AtomicOmpBuiltIn const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicOmpBuiltIn const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicOmpBuiltIn const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicOmpBuiltIn const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicOmpBuiltIn const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicOmpBuiltIn const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicOmpBuiltIn const &, T *const addr, T const &value) -> T
static ALPAKA_FN_HOST auto atomicOp(AtomicOmpBuiltIn const &, T *const addr, T const &compare, T const &value) -> T
The atomic operation trait.
Definition: Traits.hpp:60