xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/include/bits/atomic_base.h (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 // -*- C++ -*- header.
2 
3 // Copyright (C) 2008-2019 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file bits/atomic_base.h
26  *  This is an internal header file, included by other library headers.
27  *  Do not attempt to use it directly. @headername{atomic}
28  */
29 
30 #ifndef _GLIBCXX_ATOMIC_BASE_H
31 #define _GLIBCXX_ATOMIC_BASE_H 1
32 
33 #pragma GCC system_header
34 
35 #include <bits/c++config.h>
36 #include <stdint.h>
37 #include <bits/atomic_lockfree_defines.h>
38 
39 #ifndef _GLIBCXX_ALWAYS_INLINE
40 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
41 #endif
42 
43 namespace std _GLIBCXX_VISIBILITY(default)
44 {
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 
47   /**
48    * @defgroup atomics Atomics
49    *
50    * Components for performing atomic operations.
51    * @{
52    */
53 
54   /// Enumeration for memory_order
55 #if __cplusplus > 201703L
56   enum class memory_order : int
57     {
58       relaxed,
59       consume,
60       acquire,
61       release,
62       acq_rel,
63       seq_cst
64     };
65 
66   inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;
67   inline constexpr memory_order memory_order_consume = memory_order::consume;
68   inline constexpr memory_order memory_order_acquire = memory_order::acquire;
69   inline constexpr memory_order memory_order_release = memory_order::release;
70   inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;
71   inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;
72 #else
73   typedef enum memory_order
74     {
75       memory_order_relaxed,
76       memory_order_consume,
77       memory_order_acquire,
78       memory_order_release,
79       memory_order_acq_rel,
80       memory_order_seq_cst
81     } memory_order;
82 #endif
83 
84   enum __memory_order_modifier
85     {
86       __memory_order_mask          = 0x0ffff,
87       __memory_order_modifier_mask = 0xffff0000,
88       __memory_order_hle_acquire   = 0x10000,
89       __memory_order_hle_release   = 0x20000
90     };
91 
92   constexpr memory_order
93   operator|(memory_order __m, __memory_order_modifier __mod)
94   {
95     return memory_order(int(__m) | int(__mod));
96   }
97 
98   constexpr memory_order
99   operator&(memory_order __m, __memory_order_modifier __mod)
100   {
101     return memory_order(int(__m) & int(__mod));
102   }
103 
104   // Drop release ordering as per [atomics.types.operations.req]/21
105   constexpr memory_order
106   __cmpexch_failure_order2(memory_order __m) noexcept
107   {
108     return __m == memory_order_acq_rel ? memory_order_acquire
109       : __m == memory_order_release ? memory_order_relaxed : __m;
110   }
111 
112   constexpr memory_order
113   __cmpexch_failure_order(memory_order __m) noexcept
114   {
115     return memory_order(__cmpexch_failure_order2(__m & __memory_order_mask)
116       | __memory_order_modifier(__m & __memory_order_modifier_mask));
117   }
118 
119   _GLIBCXX_ALWAYS_INLINE void
120   atomic_thread_fence(memory_order __m) noexcept
121   { __atomic_thread_fence(int(__m)); }
122 
123   _GLIBCXX_ALWAYS_INLINE void
124   atomic_signal_fence(memory_order __m) noexcept
125   { __atomic_signal_fence(int(__m)); }
126 
127   /// kill_dependency
128   template<typename _Tp>
129     inline _Tp
130     kill_dependency(_Tp __y) noexcept
131     {
132       _Tp __ret(__y);
133       return __ret;
134     }
135 
136 
137   // Base types for atomics.
138   template<typename _IntTp>
139     struct __atomic_base;
140 
141 
142 #define ATOMIC_VAR_INIT(_VI) { _VI }
143 
144   template<typename _Tp>
145     struct atomic;
146 
147   template<typename _Tp>
148     struct atomic<_Tp*>;
149 
150     /* The target's "set" value for test-and-set may not be exactly 1.  */
151 #if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
152     typedef bool __atomic_flag_data_type;
153 #else
154     typedef unsigned char __atomic_flag_data_type;
155 #endif
156 
157   /**
158    *  @brief Base type for atomic_flag.
159    *
160    *  Base type is POD with data, allowing atomic_flag to derive from
161    *  it and meet the standard layout type requirement. In addition to
162    *  compatibility with a C interface, this allows different
163    *  implementations of atomic_flag to use the same atomic operation
164    *  functions, via a standard conversion to the __atomic_flag_base
165    *  argument.
166   */
167   _GLIBCXX_BEGIN_EXTERN_C
168 
169   struct __atomic_flag_base
170   {
171     __atomic_flag_data_type _M_i;
172   };
173 
174   _GLIBCXX_END_EXTERN_C
175 
176 #define ATOMIC_FLAG_INIT { 0 }
177 
178   /// atomic_flag
179   struct atomic_flag : public __atomic_flag_base
180   {
181     atomic_flag() noexcept = default;
182     ~atomic_flag() noexcept = default;
183     atomic_flag(const atomic_flag&) = delete;
184     atomic_flag& operator=(const atomic_flag&) = delete;
185     atomic_flag& operator=(const atomic_flag&) volatile = delete;
186 
187     // Conversion to ATOMIC_FLAG_INIT.
188     constexpr atomic_flag(bool __i) noexcept
189       : __atomic_flag_base{ _S_init(__i) }
190     { }
191 
192     _GLIBCXX_ALWAYS_INLINE bool
193     test_and_set(memory_order __m = memory_order_seq_cst) noexcept
194     {
195       return __atomic_test_and_set (&_M_i, int(__m));
196     }
197 
198     _GLIBCXX_ALWAYS_INLINE bool
199     test_and_set(memory_order __m = memory_order_seq_cst) volatile noexcept
200     {
201       return __atomic_test_and_set (&_M_i, int(__m));
202     }
203 
204     _GLIBCXX_ALWAYS_INLINE void
205     clear(memory_order __m = memory_order_seq_cst) noexcept
206     {
207       memory_order __b = __m & __memory_order_mask;
208       __glibcxx_assert(__b != memory_order_consume);
209       __glibcxx_assert(__b != memory_order_acquire);
210       __glibcxx_assert(__b != memory_order_acq_rel);
211 
212       __atomic_clear (&_M_i, int(__m));
213     }
214 
215     _GLIBCXX_ALWAYS_INLINE void
216     clear(memory_order __m = memory_order_seq_cst) volatile noexcept
217     {
218       memory_order __b = __m & __memory_order_mask;
219       __glibcxx_assert(__b != memory_order_consume);
220       __glibcxx_assert(__b != memory_order_acquire);
221       __glibcxx_assert(__b != memory_order_acq_rel);
222 
223       __atomic_clear (&_M_i, int(__m));
224     }
225 
226   private:
227     static constexpr __atomic_flag_data_type
228     _S_init(bool __i)
229     { return __i ? __GCC_ATOMIC_TEST_AND_SET_TRUEVAL : 0; }
230   };
231 
232 
233   /// Base class for atomic integrals.
234   //
235   // For each of the integral types, define atomic_[integral type] struct
236   //
237   // atomic_bool     bool
238   // atomic_char     char
239   // atomic_schar    signed char
240   // atomic_uchar    unsigned char
241   // atomic_short    short
242   // atomic_ushort   unsigned short
243   // atomic_int      int
244   // atomic_uint     unsigned int
245   // atomic_long     long
246   // atomic_ulong    unsigned long
247   // atomic_llong    long long
248   // atomic_ullong   unsigned long long
249   // atomic_char8_t  char8_t
250   // atomic_char16_t char16_t
251   // atomic_char32_t char32_t
252   // atomic_wchar_t  wchar_t
253   //
254   // NB: Assuming _ITp is an integral scalar type that is 1, 2, 4, or
255   // 8 bytes, since that is what GCC built-in functions for atomic
256   // memory access expect.
257   template<typename _ITp>
258     struct __atomic_base
259     {
260       using value_type = _ITp;
261       using difference_type = value_type;
262 
263     private:
264       typedef _ITp 	__int_type;
265 
266       static constexpr int _S_alignment =
267 	sizeof(_ITp) > alignof(_ITp) ? sizeof(_ITp) : alignof(_ITp);
268 
269       alignas(_S_alignment) __int_type _M_i;
270 
271     public:
272       __atomic_base() noexcept = default;
273       ~__atomic_base() noexcept = default;
274       __atomic_base(const __atomic_base&) = delete;
275       __atomic_base& operator=(const __atomic_base&) = delete;
276       __atomic_base& operator=(const __atomic_base&) volatile = delete;
277 
278       // Requires __int_type convertible to _M_i.
279       constexpr __atomic_base(__int_type __i) noexcept : _M_i (__i) { }
280 
281       operator __int_type() const noexcept
282       { return load(); }
283 
284       operator __int_type() const volatile noexcept
285       { return load(); }
286 
287       __int_type
288       operator=(__int_type __i) noexcept
289       {
290 	store(__i);
291 	return __i;
292       }
293 
294       __int_type
295       operator=(__int_type __i) volatile noexcept
296       {
297 	store(__i);
298 	return __i;
299       }
300 
301       __int_type
302       operator++(int) noexcept
303       { return fetch_add(1); }
304 
305       __int_type
306       operator++(int) volatile noexcept
307       { return fetch_add(1); }
308 
309       __int_type
310       operator--(int) noexcept
311       { return fetch_sub(1); }
312 
313       __int_type
314       operator--(int) volatile noexcept
315       { return fetch_sub(1); }
316 
317       __int_type
318       operator++() noexcept
319       { return __atomic_add_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
320 
321       __int_type
322       operator++() volatile noexcept
323       { return __atomic_add_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
324 
325       __int_type
326       operator--() noexcept
327       { return __atomic_sub_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
328 
329       __int_type
330       operator--() volatile noexcept
331       { return __atomic_sub_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
332 
333       __int_type
334       operator+=(__int_type __i) noexcept
335       { return __atomic_add_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
336 
337       __int_type
338       operator+=(__int_type __i) volatile noexcept
339       { return __atomic_add_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
340 
341       __int_type
342       operator-=(__int_type __i) noexcept
343       { return __atomic_sub_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
344 
345       __int_type
346       operator-=(__int_type __i) volatile noexcept
347       { return __atomic_sub_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
348 
349       __int_type
350       operator&=(__int_type __i) noexcept
351       { return __atomic_and_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
352 
353       __int_type
354       operator&=(__int_type __i) volatile noexcept
355       { return __atomic_and_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
356 
357       __int_type
358       operator|=(__int_type __i) noexcept
359       { return __atomic_or_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
360 
361       __int_type
362       operator|=(__int_type __i) volatile noexcept
363       { return __atomic_or_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
364 
365       __int_type
366       operator^=(__int_type __i) noexcept
367       { return __atomic_xor_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
368 
369       __int_type
370       operator^=(__int_type __i) volatile noexcept
371       { return __atomic_xor_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
372 
373       bool
374       is_lock_free() const noexcept
375       {
376 	// Use a fake, minimally aligned pointer.
377 	return __atomic_is_lock_free(sizeof(_M_i),
378 	    reinterpret_cast<void *>(-_S_alignment));
379       }
380 
381       bool
382       is_lock_free() const volatile noexcept
383       {
384 	// Use a fake, minimally aligned pointer.
385 	return __atomic_is_lock_free(sizeof(_M_i),
386 	    reinterpret_cast<void *>(-_S_alignment));
387       }
388 
389       _GLIBCXX_ALWAYS_INLINE void
390       store(__int_type __i, memory_order __m = memory_order_seq_cst) noexcept
391       {
392 	memory_order __b = __m & __memory_order_mask;
393 	__glibcxx_assert(__b != memory_order_acquire);
394 	__glibcxx_assert(__b != memory_order_acq_rel);
395 	__glibcxx_assert(__b != memory_order_consume);
396 
397 	__atomic_store_n(&_M_i, __i, int(__m));
398       }
399 
400       _GLIBCXX_ALWAYS_INLINE void
401       store(__int_type __i,
402 	    memory_order __m = memory_order_seq_cst) volatile noexcept
403       {
404 	memory_order __b = __m & __memory_order_mask;
405 	__glibcxx_assert(__b != memory_order_acquire);
406 	__glibcxx_assert(__b != memory_order_acq_rel);
407 	__glibcxx_assert(__b != memory_order_consume);
408 
409 	__atomic_store_n(&_M_i, __i, int(__m));
410       }
411 
412       _GLIBCXX_ALWAYS_INLINE __int_type
413       load(memory_order __m = memory_order_seq_cst) const noexcept
414       {
415 	memory_order __b = __m & __memory_order_mask;
416 	__glibcxx_assert(__b != memory_order_release);
417 	__glibcxx_assert(__b != memory_order_acq_rel);
418 
419 	return __atomic_load_n(&_M_i, int(__m));
420       }
421 
422       _GLIBCXX_ALWAYS_INLINE __int_type
423       load(memory_order __m = memory_order_seq_cst) const volatile noexcept
424       {
425 	memory_order __b = __m & __memory_order_mask;
426 	__glibcxx_assert(__b != memory_order_release);
427 	__glibcxx_assert(__b != memory_order_acq_rel);
428 
429 	return __atomic_load_n(&_M_i, int(__m));
430       }
431 
432       _GLIBCXX_ALWAYS_INLINE __int_type
433       exchange(__int_type __i,
434 	       memory_order __m = memory_order_seq_cst) noexcept
435       {
436 	return __atomic_exchange_n(&_M_i, __i, int(__m));
437       }
438 
439 
440       _GLIBCXX_ALWAYS_INLINE __int_type
441       exchange(__int_type __i,
442 	       memory_order __m = memory_order_seq_cst) volatile noexcept
443       {
444 	return __atomic_exchange_n(&_M_i, __i, int(__m));
445       }
446 
447       _GLIBCXX_ALWAYS_INLINE bool
448       compare_exchange_weak(__int_type& __i1, __int_type __i2,
449 			    memory_order __m1, memory_order __m2) noexcept
450       {
451 	memory_order __b2 = __m2 & __memory_order_mask;
452 	memory_order __b1 = __m1 & __memory_order_mask;
453 	__glibcxx_assert(__b2 != memory_order_release);
454 	__glibcxx_assert(__b2 != memory_order_acq_rel);
455 	__glibcxx_assert(__b2 <= __b1);
456 
457 	return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1,
458 					   int(__m1), int(__m2));
459       }
460 
461       _GLIBCXX_ALWAYS_INLINE bool
462       compare_exchange_weak(__int_type& __i1, __int_type __i2,
463 			    memory_order __m1,
464 			    memory_order __m2) volatile noexcept
465       {
466 	memory_order __b2 = __m2 & __memory_order_mask;
467 	memory_order __b1 = __m1 & __memory_order_mask;
468 	__glibcxx_assert(__b2 != memory_order_release);
469 	__glibcxx_assert(__b2 != memory_order_acq_rel);
470 	__glibcxx_assert(__b2 <= __b1);
471 
472 	return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1,
473 					   int(__m1), int(__m2));
474       }
475 
476       _GLIBCXX_ALWAYS_INLINE bool
477       compare_exchange_weak(__int_type& __i1, __int_type __i2,
478 			    memory_order __m = memory_order_seq_cst) noexcept
479       {
480 	return compare_exchange_weak(__i1, __i2, __m,
481 				     __cmpexch_failure_order(__m));
482       }
483 
484       _GLIBCXX_ALWAYS_INLINE bool
485       compare_exchange_weak(__int_type& __i1, __int_type __i2,
486 		   memory_order __m = memory_order_seq_cst) volatile noexcept
487       {
488 	return compare_exchange_weak(__i1, __i2, __m,
489 				     __cmpexch_failure_order(__m));
490       }
491 
492       _GLIBCXX_ALWAYS_INLINE bool
493       compare_exchange_strong(__int_type& __i1, __int_type __i2,
494 			      memory_order __m1, memory_order __m2) noexcept
495       {
496 	memory_order __b2 = __m2 & __memory_order_mask;
497 	memory_order __b1 = __m1 & __memory_order_mask;
498 	__glibcxx_assert(__b2 != memory_order_release);
499 	__glibcxx_assert(__b2 != memory_order_acq_rel);
500 	__glibcxx_assert(__b2 <= __b1);
501 
502 	return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 0,
503 					   int(__m1), int(__m2));
504       }
505 
506       _GLIBCXX_ALWAYS_INLINE bool
507       compare_exchange_strong(__int_type& __i1, __int_type __i2,
508 			      memory_order __m1,
509 			      memory_order __m2) volatile noexcept
510       {
511 	memory_order __b2 = __m2 & __memory_order_mask;
512 	memory_order __b1 = __m1 & __memory_order_mask;
513 
514 	__glibcxx_assert(__b2 != memory_order_release);
515 	__glibcxx_assert(__b2 != memory_order_acq_rel);
516 	__glibcxx_assert(__b2 <= __b1);
517 
518 	return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 0,
519 					   int(__m1), int(__m2));
520       }
521 
522       _GLIBCXX_ALWAYS_INLINE bool
523       compare_exchange_strong(__int_type& __i1, __int_type __i2,
524 			      memory_order __m = memory_order_seq_cst) noexcept
525       {
526 	return compare_exchange_strong(__i1, __i2, __m,
527 				       __cmpexch_failure_order(__m));
528       }
529 
530       _GLIBCXX_ALWAYS_INLINE bool
531       compare_exchange_strong(__int_type& __i1, __int_type __i2,
532 		 memory_order __m = memory_order_seq_cst) volatile noexcept
533       {
534 	return compare_exchange_strong(__i1, __i2, __m,
535 				       __cmpexch_failure_order(__m));
536       }
537 
538       _GLIBCXX_ALWAYS_INLINE __int_type
539       fetch_add(__int_type __i,
540 		memory_order __m = memory_order_seq_cst) noexcept
541       { return __atomic_fetch_add(&_M_i, __i, int(__m)); }
542 
543       _GLIBCXX_ALWAYS_INLINE __int_type
544       fetch_add(__int_type __i,
545 		memory_order __m = memory_order_seq_cst) volatile noexcept
546       { return __atomic_fetch_add(&_M_i, __i, int(__m)); }
547 
548       _GLIBCXX_ALWAYS_INLINE __int_type
549       fetch_sub(__int_type __i,
550 		memory_order __m = memory_order_seq_cst) noexcept
551       { return __atomic_fetch_sub(&_M_i, __i, int(__m)); }
552 
553       _GLIBCXX_ALWAYS_INLINE __int_type
554       fetch_sub(__int_type __i,
555 		memory_order __m = memory_order_seq_cst) volatile noexcept
556       { return __atomic_fetch_sub(&_M_i, __i, int(__m)); }
557 
558       _GLIBCXX_ALWAYS_INLINE __int_type
559       fetch_and(__int_type __i,
560 		memory_order __m = memory_order_seq_cst) noexcept
561       { return __atomic_fetch_and(&_M_i, __i, int(__m)); }
562 
563       _GLIBCXX_ALWAYS_INLINE __int_type
564       fetch_and(__int_type __i,
565 		memory_order __m = memory_order_seq_cst) volatile noexcept
566       { return __atomic_fetch_and(&_M_i, __i, int(__m)); }
567 
568       _GLIBCXX_ALWAYS_INLINE __int_type
569       fetch_or(__int_type __i,
570 	       memory_order __m = memory_order_seq_cst) noexcept
571       { return __atomic_fetch_or(&_M_i, __i, int(__m)); }
572 
573       _GLIBCXX_ALWAYS_INLINE __int_type
574       fetch_or(__int_type __i,
575 	       memory_order __m = memory_order_seq_cst) volatile noexcept
576       { return __atomic_fetch_or(&_M_i, __i, int(__m)); }
577 
578       _GLIBCXX_ALWAYS_INLINE __int_type
579       fetch_xor(__int_type __i,
580 		memory_order __m = memory_order_seq_cst) noexcept
581       { return __atomic_fetch_xor(&_M_i, __i, int(__m)); }
582 
583       _GLIBCXX_ALWAYS_INLINE __int_type
584       fetch_xor(__int_type __i,
585 		memory_order __m = memory_order_seq_cst) volatile noexcept
586       { return __atomic_fetch_xor(&_M_i, __i, int(__m)); }
587     };
588 
589 
590   /// Partial specialization for pointer types.
591   template<typename _PTp>
592     struct __atomic_base<_PTp*>
593     {
594     private:
595       typedef _PTp* 	__pointer_type;
596 
597       __pointer_type 	_M_p;
598 
599       // Factored out to facilitate explicit specialization.
600       constexpr ptrdiff_t
601       _M_type_size(ptrdiff_t __d) const { return __d * sizeof(_PTp); }
602 
603       constexpr ptrdiff_t
604       _M_type_size(ptrdiff_t __d) const volatile { return __d * sizeof(_PTp); }
605 
606     public:
607       __atomic_base() noexcept = default;
608       ~__atomic_base() noexcept = default;
609       __atomic_base(const __atomic_base&) = delete;
610       __atomic_base& operator=(const __atomic_base&) = delete;
611       __atomic_base& operator=(const __atomic_base&) volatile = delete;
612 
613       // Requires __pointer_type convertible to _M_p.
614       constexpr __atomic_base(__pointer_type __p) noexcept : _M_p (__p) { }
615 
616       operator __pointer_type() const noexcept
617       { return load(); }
618 
619       operator __pointer_type() const volatile noexcept
620       { return load(); }
621 
622       __pointer_type
623       operator=(__pointer_type __p) noexcept
624       {
625 	store(__p);
626 	return __p;
627       }
628 
629       __pointer_type
630       operator=(__pointer_type __p) volatile noexcept
631       {
632 	store(__p);
633 	return __p;
634       }
635 
636       __pointer_type
637       operator++(int) noexcept
638       { return fetch_add(1); }
639 
640       __pointer_type
641       operator++(int) volatile noexcept
642       { return fetch_add(1); }
643 
644       __pointer_type
645       operator--(int) noexcept
646       { return fetch_sub(1); }
647 
648       __pointer_type
649       operator--(int) volatile noexcept
650       { return fetch_sub(1); }
651 
652       __pointer_type
653       operator++() noexcept
654       { return __atomic_add_fetch(&_M_p, _M_type_size(1),
655 				  int(memory_order_seq_cst)); }
656 
657       __pointer_type
658       operator++() volatile noexcept
659       { return __atomic_add_fetch(&_M_p, _M_type_size(1),
660 				  int(memory_order_seq_cst)); }
661 
662       __pointer_type
663       operator--() noexcept
664       { return __atomic_sub_fetch(&_M_p, _M_type_size(1),
665 				  int(memory_order_seq_cst)); }
666 
667       __pointer_type
668       operator--() volatile noexcept
669       { return __atomic_sub_fetch(&_M_p, _M_type_size(1),
670 				  int(memory_order_seq_cst)); }
671 
672       __pointer_type
673       operator+=(ptrdiff_t __d) noexcept
674       { return __atomic_add_fetch(&_M_p, _M_type_size(__d),
675 				  int(memory_order_seq_cst)); }
676 
677       __pointer_type
678       operator+=(ptrdiff_t __d) volatile noexcept
679       { return __atomic_add_fetch(&_M_p, _M_type_size(__d),
680 				  int(memory_order_seq_cst)); }
681 
682       __pointer_type
683       operator-=(ptrdiff_t __d) noexcept
684       { return __atomic_sub_fetch(&_M_p, _M_type_size(__d),
685 				  int(memory_order_seq_cst)); }
686 
687       __pointer_type
688       operator-=(ptrdiff_t __d) volatile noexcept
689       { return __atomic_sub_fetch(&_M_p, _M_type_size(__d),
690 				  int(memory_order_seq_cst)); }
691 
692       bool
693       is_lock_free() const noexcept
694       {
695 	// Produce a fake, minimally aligned pointer.
696 	return __atomic_is_lock_free(sizeof(_M_p),
697 	    reinterpret_cast<void *>(-__alignof(_M_p)));
698       }
699 
700       bool
701       is_lock_free() const volatile noexcept
702       {
703 	// Produce a fake, minimally aligned pointer.
704 	return __atomic_is_lock_free(sizeof(_M_p),
705 	    reinterpret_cast<void *>(-__alignof(_M_p)));
706       }
707 
708       _GLIBCXX_ALWAYS_INLINE void
709       store(__pointer_type __p,
710 	    memory_order __m = memory_order_seq_cst) noexcept
711       {
712         memory_order __b = __m & __memory_order_mask;
713 
714 	__glibcxx_assert(__b != memory_order_acquire);
715 	__glibcxx_assert(__b != memory_order_acq_rel);
716 	__glibcxx_assert(__b != memory_order_consume);
717 
718 	__atomic_store_n(&_M_p, __p, int(__m));
719       }
720 
721       _GLIBCXX_ALWAYS_INLINE void
722       store(__pointer_type __p,
723 	    memory_order __m = memory_order_seq_cst) volatile noexcept
724       {
725 	memory_order __b = __m & __memory_order_mask;
726 	__glibcxx_assert(__b != memory_order_acquire);
727 	__glibcxx_assert(__b != memory_order_acq_rel);
728 	__glibcxx_assert(__b != memory_order_consume);
729 
730 	__atomic_store_n(&_M_p, __p, int(__m));
731       }
732 
733       _GLIBCXX_ALWAYS_INLINE __pointer_type
734       load(memory_order __m = memory_order_seq_cst) const noexcept
735       {
736 	memory_order __b = __m & __memory_order_mask;
737 	__glibcxx_assert(__b != memory_order_release);
738 	__glibcxx_assert(__b != memory_order_acq_rel);
739 
740 	return __atomic_load_n(&_M_p, int(__m));
741       }
742 
743       _GLIBCXX_ALWAYS_INLINE __pointer_type
744       load(memory_order __m = memory_order_seq_cst) const volatile noexcept
745       {
746 	memory_order __b = __m & __memory_order_mask;
747 	__glibcxx_assert(__b != memory_order_release);
748 	__glibcxx_assert(__b != memory_order_acq_rel);
749 
750 	return __atomic_load_n(&_M_p, int(__m));
751       }
752 
753       _GLIBCXX_ALWAYS_INLINE __pointer_type
754       exchange(__pointer_type __p,
755 	       memory_order __m = memory_order_seq_cst) noexcept
756       {
757 	return __atomic_exchange_n(&_M_p, __p, int(__m));
758       }
759 
760 
761       _GLIBCXX_ALWAYS_INLINE __pointer_type
762       exchange(__pointer_type __p,
763 	       memory_order __m = memory_order_seq_cst) volatile noexcept
764       {
765 	return __atomic_exchange_n(&_M_p, __p, int(__m));
766       }
767 
768       _GLIBCXX_ALWAYS_INLINE bool
769       compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
770 			      memory_order __m1,
771 			      memory_order __m2) noexcept
772       {
773 	memory_order __b2 = __m2 & __memory_order_mask;
774 	memory_order __b1 = __m1 & __memory_order_mask;
775 	__glibcxx_assert(__b2 != memory_order_release);
776 	__glibcxx_assert(__b2 != memory_order_acq_rel);
777 	__glibcxx_assert(__b2 <= __b1);
778 
779 	return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 0,
780 					   int(__m1), int(__m2));
781       }
782 
783       _GLIBCXX_ALWAYS_INLINE bool
784       compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
785 			      memory_order __m1,
786 			      memory_order __m2) volatile noexcept
787       {
788 	memory_order __b2 = __m2 & __memory_order_mask;
789 	memory_order __b1 = __m1 & __memory_order_mask;
790 
791 	__glibcxx_assert(__b2 != memory_order_release);
792 	__glibcxx_assert(__b2 != memory_order_acq_rel);
793 	__glibcxx_assert(__b2 <= __b1);
794 
795 	return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 0,
796 					   int(__m1), int(__m2));
797       }
798 
799       _GLIBCXX_ALWAYS_INLINE __pointer_type
800       fetch_add(ptrdiff_t __d,
801 		memory_order __m = memory_order_seq_cst) noexcept
802       { return __atomic_fetch_add(&_M_p, _M_type_size(__d), int(__m)); }
803 
804       _GLIBCXX_ALWAYS_INLINE __pointer_type
805       fetch_add(ptrdiff_t __d,
806 		memory_order __m = memory_order_seq_cst) volatile noexcept
807       { return __atomic_fetch_add(&_M_p, _M_type_size(__d), int(__m)); }
808 
809       _GLIBCXX_ALWAYS_INLINE __pointer_type
810       fetch_sub(ptrdiff_t __d,
811 		memory_order __m = memory_order_seq_cst) noexcept
812       { return __atomic_fetch_sub(&_M_p, _M_type_size(__d), int(__m)); }
813 
814       _GLIBCXX_ALWAYS_INLINE __pointer_type
815       fetch_sub(ptrdiff_t __d,
816 		memory_order __m = memory_order_seq_cst) volatile noexcept
817       { return __atomic_fetch_sub(&_M_p, _M_type_size(__d), int(__m)); }
818     };
819 
820   // @} group atomics
821 
822 _GLIBCXX_END_NAMESPACE_VERSION
823 } // namespace std
824 
825 #endif
826