diff options
Diffstat (limited to 'test/CodeGen/atomic-ops.c')
-rw-r--r-- | test/CodeGen/atomic-ops.c | 178 |
1 files changed, 165 insertions, 13 deletions
diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c index 9e6b4805e8cb..559b13541323 100644 --- a/test/CodeGen/atomic-ops.c +++ b/test/CodeGen/atomic-ops.c @@ -1,18 +1,15 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -ffreestanding -triple=i686-apple-darwin9 | FileCheck %s // Also test serialization of atomic operations here, to avoid duplicating the // test. -// RUN: %clang_cc1 %s -emit-pch -o %t -triple=i686-apple-darwin9 -// RUN: %clang_cc1 %s -include-pch %t -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -emit-pch -o %t -ffreestanding -triple=i686-apple-darwin9 +// RUN: %clang_cc1 %s -include-pch %t -ffreestanding -triple=i686-apple-darwin9 -emit-llvm -o - | FileCheck %s #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 @@ -34,6 +31,12 @@ int fi1b(int *i) { 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 @@ -53,6 +56,12 @@ void fi2b(int *i) { __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 @@ -89,8 +98,15 @@ int fi3d(int *i) { 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 @@ -101,7 +117,7 @@ _Bool fi4(_Atomic(int) *i) { } _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 @@ -113,7 +129,7 @@ _Bool fi4a(int *i) { } _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 @@ -123,6 +139,13 @@ _Bool fi4b(int *i) { 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 @@ -139,6 +162,79 @@ float ff3(_Atomic(float) *d) { return __c11_atomic_exchange(d, 2, memory_order_seq_cst); } +struct S { + double x; +}; + +struct S fd1(struct S *a) { + // CHECK-LABEL: @fd1 + // CHECK: [[RETVAL:%.*]] = alloca %struct.S, align 4 + // CHECK: [[RET:%.*]] = alloca %struct.S, align 4 + // CHECK: [[CALL:%.*]] = call i64 @__atomic_load_8( + // CHECK: [[CAST:%.*]] = bitcast %struct.S* [[RET]] to i64* + // CHECK: store i64 [[CALL]], i64* [[CAST]], align 4 + struct S ret; + __atomic_load(a, &ret, memory_order_seq_cst); + return ret; +} + +void fd2(struct S *a, struct S *b) { + // CHECK-LABEL: @fd2 + // CHECK: [[A_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK-NEXT: [[B_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK-NEXT: store %struct.S* %a, %struct.S** [[A_ADDR]], align 4 + // CHECK-NEXT: store %struct.S* %b, %struct.S** [[B_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load %struct.S** [[A_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load %struct.S** [[B_ADDR]], align 4 + // CHECK-NEXT: [[COERCED_A:%.*]] = bitcast %struct.S* [[LOAD_A_PTR]] to i8* + // CHECK-NEXT: [[COERCED_B:%.*]] = bitcast %struct.S* [[LOAD_B_PTR]] to i64* + // CHECK-NEXT: [[LOAD_B:%.*]] = load i64* [[COERCED_B]], align 4 + // CHECK-NEXT: call void @__atomic_store_8(i8* [[COERCED_A]], i64 [[LOAD_B]], + // CHECK-NEXT: ret void + __atomic_store(a, b, memory_order_seq_cst); +} + +void fd3(struct S *a, struct S *b, struct S *c) { + // CHECK-LABEL: @fd3 + // CHECK: [[A_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK-NEXT: [[B_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK-NEXT: [[C_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK-NEXT: store %struct.S* %a, %struct.S** [[A_ADDR]], align 4 + // CHECK-NEXT: store %struct.S* %b, %struct.S** [[B_ADDR]], align 4 + // CHECK-NEXT: store %struct.S* %c, %struct.S** [[C_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load %struct.S** [[A_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load %struct.S** [[B_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_C_PTR:%.*]] = load %struct.S** [[C_ADDR]], align 4 + // CHECK-NEXT: [[COERCED_A:%.*]] = bitcast %struct.S* [[LOAD_A_PTR]] to i8* + // CHECK-NEXT: [[COERCED_B:%.*]] = bitcast %struct.S* [[LOAD_B_PTR]] to i64* + // CHECK-NEXT: [[LOAD_B:%.*]] = load i64* [[COERCED_B]], align 4 + // CHECK-NEXT: [[CALL:%.*]] = call i64 @__atomic_exchange_8(i8* [[COERCED_A]], i64 [[LOAD_B]], + // CHECK-NEXT: [[COERCED_C:%.*]] = bitcast %struct.S* [[LOAD_C_PTR]] to i64* + // CHECK-NEXT: store i64 [[CALL]], i64* [[COERCED_C]], align 4 + + __atomic_exchange(a, b, c, memory_order_seq_cst); +} + +_Bool fd4(struct S *a, struct S *b, struct S *c) { + // CHECK-LABEL: @fd4 + // CHECK: [[A_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK-NEXT: [[B_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK-NEXT: [[C_ADDR:%.*]] = alloca %struct.S*, align 4 + // CHECK: store %struct.S* %a, %struct.S** [[A_ADDR]], align 4 + // CHECK-NEXT: store %struct.S* %b, %struct.S** [[B_ADDR]], align 4 + // CHECK-NEXT: store %struct.S* %c, %struct.S** [[C_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load %struct.S** [[A_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load %struct.S** [[B_ADDR]], align 4 + // CHECK-NEXT: [[LOAD_C_PTR:%.*]] = load %struct.S** [[C_ADDR]], align 4 + // CHECK-NEXT: [[COERCED_A:%.*]] = bitcast %struct.S* [[LOAD_A_PTR]] to i8* + // CHECK-NEXT: [[COERCED_B:%.*]] = bitcast %struct.S* [[LOAD_B_PTR]] to i8* + // CHECK-NEXT: [[COERCED_C:%.*]] = bitcast %struct.S* [[LOAD_C_PTR]] to i64* + // CHECK-NEXT: [[LOAD_C:%.*]] = load i64* [[COERCED_C]], align 4 + // CHECK-NEXT: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange_8(i8* [[COERCED_A]], i8* [[COERCED_B]], i64 [[LOAD_C]] + // CHECK-NEXT: ret i1 [[CALL]] + return __atomic_compare_exchange(a, b, c, 1, 5, 5); +} + int* fp1(_Atomic(int*) *p) { // CHECK-LABEL: @fp1 // CHECK: load atomic i32* {{.*}} seq_cst @@ -287,14 +383,23 @@ struct foo structAtomicExchange() { } int structAtomicCmpExchange() { // CHECK-LABEL: @structAtomicCmpExchange + // CHECK: %[[x_mem:.*]] = alloca i8 _Bool x = __atomic_compare_exchange(&smallThing, &thing1, &thing2, 1, 5, 5); - // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2 + // CHECK: %[[call1:.*]] = call zeroext i1 @__atomic_compare_exchange(i32 3, {{.*}} @smallThing{{.*}} @thing1{{.*}} @thing2 + // CHECK: %[[zext1:.*]] = zext i1 %[[call1]] to i8 + // CHECK: store i8 %[[zext1]], i8* %[[x_mem]], align 1 + // CHECK: %[[x:.*]] = load i8* %[[x_mem]] + // CHECK: %[[x_bool:.*]] = trunc i8 %[[x]] to i1 + // CHECK: %[[conv1:.*]] = zext i1 %[[x_bool]] to i32 struct foo f = {0}; struct foo g = {0}; g.big[12] = 12; return x & __c11_atomic_compare_exchange_strong(&bigAtomic, &f, g, 5, 5); - // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*), + // CHECK: %[[call2:.*]] = call zeroext i1 @__atomic_compare_exchange(i32 512, i8* bitcast ({{.*}} @bigAtomic to i8*), + // CHECK: %[[conv2:.*]] = zext i1 %[[call2]] to i32 + // CHECK: %[[and:.*]] = and i32 %[[conv1]], %[[conv2]] + // CHECK: ret i32 %[[and]] } // Check that no atomic operations are used in any initialisation of _Atomic @@ -447,4 +552,51 @@ void EMIT_ALL_THE_THINGS(int *ptr, int *ptr2, int new, _Bool weak, int success, // CHECK: = cmpxchg weak {{.*}} seq_cst seq_cst } +int PR21643() { + return __atomic_or_fetch((int __attribute__((address_space(257))) *)0x308, 1, + __ATOMIC_RELAXED); + // CHECK: %[[atomictmp:.*]] = alloca i32, align 4 + // CHECK: %[[atomicdst:.*]] = alloca i32, align 4 + // CHECK: store i32 1, i32* %[[atomictmp]] + // CHECK: %[[one:.*]] = load i32* %[[atomictmp]], align 4 + // CHECK: %[[old:.*]] = atomicrmw or i32 addrspace(257)* inttoptr (i32 776 to i32 addrspace(257)*), i32 %[[one]] monotonic + // CHECK: %[[new:.*]] = or i32 %[[old]], %[[one]] + // CHECK: store i32 %[[new]], i32* %[[atomicdst]], align 4 + // CHECK: %[[ret:.*]] = load i32* %[[atomicdst]], align 4 + // CHECK: ret i32 %[[ret]] +} + +int PR17306_1(volatile _Atomic(int) *i) { + // CHECK-LABEL: @PR17306_1 + // CHECK: %[[i_addr:.*]] = alloca i32 + // CHECK-NEXT: %[[atomicdst:.*]] = alloca i32 + // CHECK-NEXT: store i32* %i, i32** %[[i_addr]] + // CHECK-NEXT: %[[addr:.*]] = load i32** %[[i_addr]] + // CHECK-NEXT: %[[res:.*]] = load atomic volatile i32* %[[addr]] seq_cst + // CHECK-NEXT: store i32 %[[res]], i32* %[[atomicdst]] + // CHECK-NEXT: %[[retval:.*]] = load i32* %[[atomicdst]] + // CHECK-NEXT: ret i32 %[[retval]] + return __c11_atomic_load(i, memory_order_seq_cst); +} + +int PR17306_2(volatile int *i, int value) { + // CHECK-LABEL: @PR17306_2 + // CHECK: %[[i_addr:.*]] = alloca i32* + // CHECK-NEXT: %[[value_addr:.*]] = alloca i32 + // CHECK-NEXT: %[[atomictmp:.*]] = alloca i32 + // CHECK-NEXT: %[[atomicdst:.*]] = alloca i32 + // CHECK-NEXT: store i32* %i, i32** %[[i_addr]] + // CHECK-NEXT: store i32 %value, i32* %[[value_addr]] + // CHECK-NEXT: %[[i_lval:.*]] = load i32** %[[i_addr]] + // CHECK-NEXT: %[[value:.*]] = load i32* %[[value_addr]] + // CHECK-NEXT: store i32 %[[value]], i32* %[[atomictmp]] + // CHECK-NEXT: %[[value_lval:.*]] = load i32* %[[atomictmp]] + // CHECK-NEXT: %[[old_val:.*]] = atomicrmw volatile add i32* %[[i_lval]], i32 %[[value_lval]] seq_cst + // CHECK-NEXT: %[[new_val:.*]] = add i32 %[[old_val]], %[[value_lval]] + // CHECK-NEXT: store i32 %[[new_val]], i32* %[[atomicdst]] + // CHECK-NEXT: %[[retval:.*]] = load i32* %[[atomicdst]] + // CHECK-NEXT: ret i32 %[[retval]] + return __atomic_add_fetch(i, value, memory_order_seq_cst); +} + #endif |