Use ``__has_feature(c_atomic)`` or ``__has_extension(c_atomic)`` to determine
if support for atomic types using ``_Atomic`` is enabled. Clang also provides
:ref:`a set of builtins <langext-__c11_atomic>` which can be used to implement
-the ``<stdatomic.h>`` operations on ``_Atomic`` types.
+the ``<stdatomic.h>`` operations on ``_Atomic`` types. Use
+``__has_include(<stdatomic.h>)`` to determine if C11's ``<stdatomic.h>`` header
+is available.
+
+Clang will use the system's ``<stdatomic.h>`` header when one is available, and
+will otherwise use its own. When using its own, implementations of the atomic
+operations are provided as macros. In the cases where C11 also requires a real
+function, this header provides only the declaration of that function (along
+with a shadowing macro implementation), and you must link to a library which
+provides a definition of the function if you use it instead of the macro.
C11 generic selections
^^^^^^^^^^^^^^^^^^^^^^
Clang provides a set of builtins which are intended to be used to implement
C11's ``<stdatomic.h>`` header. These builtins provide the semantics of the
``_explicit`` form of the corresponding C11 operation, and are named with a
-``__c11_`` prefix. The supported operations are:
+``__c11_`` prefix. The supported operations, and the differences from
+the corresponding C11 operations, are:
* ``__c11_atomic_init``
* ``__c11_atomic_thread_fence``
* ``__c11_atomic_signal_fence``
-* ``__c11_atomic_is_lock_free``
+* ``__c11_atomic_is_lock_free`` (The argument is the size of the
+ ``_Atomic(...)'' object, instead of its address)
* ``__c11_atomic_store``
* ``__c11_atomic_load``
* ``__c11_atomic_exchange``
* ``__c11_atomic_fetch_or``
* ``__c11_atomic_fetch_xor``
+The macros ``__ATOMIC_RELAXED``, ``__ATOMIC_CONSUME``, ``__ATOMIC_ACQUIRE``,
+``__ATOMIC_RELEASE``, ``__ATOMIC_ACQ_REL``, and ``_ATOMIC_SEQ_CST`` are
+provided, with values corresponding to the enumerators of C11's
+``memory_order`` enumeration.
+
Low-level ARM exclusive memory builtins
---------------------------------------
smmintrin.h
stdalign.h
stdarg.h
+ stdatomic.h
stdbool.h
stddef.h
__stddef_max_align_t.h
--- /dev/null
+/*===---- stdatomic.h - Standard header for atomic types and operations -----===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __CLANG_STDATOMIC_H
+#define __CLANG_STDATOMIC_H
+
+/* If we're hosted, fall back to the system's stdatomic.h. FreeBSD, for
+ * example, already has a Clang-compatible stdatomic.h header.
+ */
+#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>)
+# include_next <stdatomic.h>
+#else
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 7.17.1 Introduction */
+
+#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
+#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
+#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
+#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
+#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#define ATOMIC_SHORT_T_LOCK_FREE __GCC_ATOMIC_SHORT_T_LOCK_FREE
+#define ATOMIC_INT_T_LOCK_FREE __GCC_ATOMIC_INT_T_LOCK_FREE
+#define ATOMIC_LONG_T_LOCK_FREE __GCC_ATOMIC_LONG_T_LOCK_FREE
+#define ATOMIC_LLONG_T_LOCK_FREE __GCC_ATOMIC_LLONG_T_LOCK_FREE
+#define ATOMIC_POINTER_T_LOCK_FREE __GCC_ATOMIC_POINTER_T_LOCK_FREE
+
+/* 7.17.2 Initialization */
+
+#define ATOMIC_VAR_INIT(value) (value)
+#define atomic_init __c11_atomic_init
+
+/* 7.17.3 Order and consistency */
+
+typedef enum memory_order {
+ memory_order_relaxed = __ATOMIC_RELAXED,
+ memory_order_consume = __ATOMIC_CONSUME,
+ memory_order_acquire = __ATOMIC_ACQUIRE,
+ memory_order_release = __ATOMIC_RELEASE,
+ memory_order_acq_rel = __ATOMIC_ACQ_REL,
+ memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+#define kill_dependency(y) (y)
+
+/* 7.17.4 Fences */
+
+// These should be provided by the libc implementation.
+void atomic_thread_fence(memory_order);
+void atomic_signal_fence(memory_order);
+
+#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
+#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
+
+/* 7.17.5 Lock-free property */
+
+#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj)))
+
+/* 7.17.6 Atomic integer types */
+
+#ifdef __cplusplus
+typedef _Atomic(bool) atomic_bool;
+#else
+typedef _Atomic(_Bool) atomic_bool;
+#endif
+typedef _Atomic(char) atomic_char;
+typedef _Atomic(signed char) atomic_schar;
+typedef _Atomic(unsigned char) atomic_uchar;
+typedef _Atomic(short) atomic_short;
+typedef _Atomic(unsigned short) atomic_ushort;
+typedef _Atomic(int) atomic_int;
+typedef _Atomic(unsigned int) atomic_uint;
+typedef _Atomic(long) atomic_long;
+typedef _Atomic(unsigned long) atomic_ulong;
+typedef _Atomic(long long) atomic_llong;
+typedef _Atomic(unsigned long long) atomic_ullong;
+typedef _Atomic(uint_least16_t) atomic_char16_t;
+typedef _Atomic(uint_least32_t) atomic_char32_t;
+typedef _Atomic(wchar_t) atomic_wchar_t;
+typedef _Atomic(int_least8_t) atomic_int_least8_t;
+typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
+typedef _Atomic(int_least16_t) atomic_int_least16_t;
+typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
+typedef _Atomic(int_least32_t) atomic_int_least32_t;
+typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
+typedef _Atomic(int_least64_t) atomic_int_least64_t;
+typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
+typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
+typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
+typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
+typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
+typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
+typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
+typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
+typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
+typedef _Atomic(intptr_t) atomic_intptr_t;
+typedef _Atomic(uintptr_t) atomic_uintptr_t;
+typedef _Atomic(size_t) atomic_size_t;
+typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
+typedef _Atomic(intmax_t) atomic_intmax_t;
+typedef _Atomic(uintmax_t) atomic_uintmax_t;
+
+/* 7.17.7 Operations on atomic types */
+
+#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST)
+#define atomic_store_explicit __c11_atomic_store
+
+#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST)
+#define atomic_load_explicit __c11_atomic_load
+
+#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST)
+#define atomic_exchange_explicit __c11_atomic_exchange
+
+#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong
+
+#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak
+
+#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_add_explicit __c11_atomic_fetch_add
+
+#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub
+
+#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_or_explicit __c11_atomic_fetch_or
+
+#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor
+
+#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_and_explicit __c11_atomic_fetch_and
+
+/* 7.17.8 Atomic flag type and operations */
+
+typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
+
+#define ATOMIC_FLAG_INIT { 0 }
+
+// These should be provided by the libc implementation.
+#ifdef __cplusplus
+bool atomic_flag_test_and_set(volatile atomic_flag *);
+bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
+#else
+_Bool atomic_flag_test_and_set(volatile atomic_flag *);
+_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
+#endif
+void atomic_flag_clear(volatile atomic_flag *);
+void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order);
+
+#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST)
+#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order)
+
+#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST)
+#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STDC_HOSTED__ */
+#endif /* __CLANG_STDATOMIC_H */
+
#ifndef ALREADY_INCLUDED
#define ALREADY_INCLUDED
-// Basic IRGen tests for __c11_atomic_* and GNU __atomic_*
+#include <stdatomic.h>
-typedef enum memory_order {
- memory_order_relaxed, memory_order_consume, memory_order_acquire,
- memory_order_release, memory_order_acq_rel, memory_order_seq_cst
-} memory_order;
+// Basic IRGen tests for __c11_atomic_* and GNU __atomic_*
int fi1(_Atomic(int) *i) {
// CHECK-LABEL: @fi1
return __atomic_load_n(i, memory_order_seq_cst);
}
+int fi1c(atomic_int *i) {
+ // CHECK-LABEL: @fi1c
+ // CHECK: load atomic i32* {{.*}} seq_cst
+ return atomic_load(i);
+}
+
void fi2(_Atomic(int) *i) {
// CHECK-LABEL: @fi2
// CHECK: store atomic i32 {{.*}} seq_cst
__atomic_store_n(i, 1, memory_order_seq_cst);
}
+void fi2c(atomic_int *i) {
+ // CHECK-LABEL: @fi2c
+ // CHECK: store atomic i32 {{.*}} seq_cst
+ atomic_store(i, 1);
+}
+
int fi3(_Atomic(int) *i) {
// CHECK-LABEL: @fi3
// CHECK: atomicrmw and
return __atomic_nand_fetch(i, 1, memory_order_seq_cst);
}
+int fi3e(atomic_int *i) {
+ // CHECK-LABEL: @fi3e
+ // CHECK: atomicrmw or
+ // CHECK-NOT: {{ or }}
+ return atomic_fetch_or(i, 1);
+}
+
_Bool fi4(_Atomic(int) *i) {
- // CHECK-LABEL: @fi4
+ // CHECK-LABEL: @fi4(
// CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]]
// CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
// CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
}
_Bool fi4a(int *i) {
- // CHECK-LABEL: @fi4
+ // CHECK-LABEL: @fi4a
// CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]]
// CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
// CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
}
_Bool fi4b(int *i) {
- // CHECK-LABEL: @fi4
+ // CHECK-LABEL: @fi4b(
// CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg weak i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]]
// CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0
// CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1
return __atomic_compare_exchange_n(i, &cmp, 1, 1, memory_order_acquire, memory_order_acquire);
}
+_Bool fi4c(atomic_int *i) {
+ // CHECK-LABEL: @fi4c
+ // CHECK: cmpxchg i32*
+ int cmp = 0;
+ return atomic_compare_exchange_strong(i, &cmp, 1);
+}
+
float ff1(_Atomic(float) *d) {
// CHECK-LABEL: @ff1
// CHECK: load atomic i32* {{.*}} monotonic
// Basic parsing/Sema tests for __c11_atomic_*
-typedef enum memory_order {
- memory_order_relaxed, memory_order_consume, memory_order_acquire,
- memory_order_release, memory_order_acq_rel, memory_order_seq_cst
-} memory_order;
+#include <stdatomic.h>
struct S { char c[3]; };
_Static_assert(__atomic_is_lock_free(16, 0), ""); // expected-error {{not an integral constant expression}}
_Static_assert(__atomic_is_lock_free(17, 0), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(atomic_is_lock_free((atomic_char*)0), "");
+_Static_assert(atomic_is_lock_free((atomic_short*)0), "");
+_Static_assert(atomic_is_lock_free((atomic_int*)0), "");
+_Static_assert(atomic_is_lock_free((atomic_long*)0), "");
+// expected-error@+1 {{__int128 is not supported on this target}}
+_Static_assert(atomic_is_lock_free((_Atomic(__int128)*)0), ""); // expected-error {{not an integral constant expression}}
+_Static_assert(atomic_is_lock_free(0 + (atomic_char*)0), "");
+
char i8;
short i16;
int i32;
__c11_atomic_init(&const_atomic, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
__c11_atomic_store(&const_atomic, 0, memory_order_release); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
__c11_atomic_load(&const_atomic, memory_order_acquire); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}}
+
+ // Ensure the <stdatomic.h> macros behave appropriately.
+ atomic_int n = ATOMIC_VAR_INIT(123);
+ atomic_init(&n, 456);
+ atomic_init(&n, (void*)0); // expected-warning {{passing 'void *' to parameter of type 'int'}}
+
+ const atomic_wchar_t cawt;
+ atomic_init(&cawt, L'x'); // expected-error {{non-const}}
+ atomic_wchar_t awt;
+ atomic_init(&awt, L'x');
+
+ int x = kill_dependency(12);
+
+ atomic_thread_fence(); // expected-error {{too few arguments to function call}}
+ atomic_thread_fence(memory_order_seq_cst);
+ atomic_signal_fence(memory_order_seq_cst);
+ void (*pfn)(memory_order) = &atomic_thread_fence;
+ pfn = &atomic_signal_fence;
+
+ int k = atomic_load_explicit(&n, memory_order_relaxed);
+ atomic_store_explicit(&n, k, memory_order_relaxed);
+ atomic_store(&n, atomic_load(&n));
+
+ k = atomic_exchange(&n, 72);
+ k = atomic_exchange_explicit(&n, k, memory_order_release);
+
+ atomic_compare_exchange_strong(&n, k, k); // expected-warning {{take the address with &}}
+ atomic_compare_exchange_weak(&n, &k, k);
+ atomic_compare_exchange_strong_explicit(&n, &k, k, memory_order_seq_cst); // expected-error {{too few arguments}}
+ atomic_compare_exchange_weak_explicit(&n, &k, k, memory_order_seq_cst, memory_order_acquire);
+
+ atomic_fetch_add(&k, n); // expected-error {{must be a pointer to _Atomic}}
+ k = atomic_fetch_add(&n, k);
+ k = atomic_fetch_sub(&n, k);
+ k = atomic_fetch_and(&n, k);
+ k = atomic_fetch_or(&n, k);
+ k = atomic_fetch_xor(&n, k);
+ k = atomic_fetch_add_explicit(&n, k, memory_order_acquire);
+ k = atomic_fetch_sub_explicit(&n, k, memory_order_release);
+ k = atomic_fetch_and_explicit(&n, k, memory_order_acq_rel);
+ k = atomic_fetch_or_explicit(&n, k, memory_order_consume);
+ k = atomic_fetch_xor_explicit(&n, k, memory_order_relaxed);
+
+ // C11 7.17.1/4: atomic_flag is a structure type.
+ struct atomic_flag must_be_struct = ATOMIC_FLAG_INIT;
+ // C11 7.17.8/5 implies that it is also a typedef type.
+ atomic_flag guard = ATOMIC_FLAG_INIT;
+ _Bool old_val = atomic_flag_test_and_set(&guard);
+ if (old_val) atomic_flag_clear(&guard);
+
+ old_val = (atomic_flag_test_and_set)(&guard);
+ if (old_val) (atomic_flag_clear)(&guard);
+
+ const atomic_flag const_guard;
+ atomic_flag_test_and_set(&const_guard); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_bool *' (aka 'const _Atomic(_Bool) *') invalid)}}
+ atomic_flag_clear(&const_guard); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_bool *' (aka 'const _Atomic(_Bool) *') invalid)}}
}
_Atomic(int*) PR12527_a;
(void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_acq_rel, memory_order_relaxed);
(void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, memory_order_relaxed);
}
+
+