diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -138,18 +138,22 @@ void ARMTargetInfo::setAtomic() { // when triple does not specify a sub arch, // then we are not using inline atomics - bool ShouldUseInlineAtomic = - (ArchISA == llvm::ARM::ISAKind::ARM && ArchVersion >= 6) || - (ArchISA == llvm::ARM::ISAKind::THUMB && ArchVersion >= 7); - // Cortex M does not support 8 byte atomics, while general Thumb2 does. if (ArchProfile == llvm::ARM::ProfileKind::M) { + // Cortex-M besides Cortex-M0 has 32-bit atomics. + // + // Cortex-M0 is missing ldrex/strex, so we generate __sync_* calls. (In + // most cases, these can be implemented by disabling interrupts.) MaxAtomicPromoteWidth = 32; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 32; + MaxAtomicInlineWidth = 32; } else { + // v7 has 64-bit atomics. Some v6 variants have 64-bit atomics, some + // have 32-bit atomics. Older variants have no atomics, but they + // might be emulated on some targets. We completely ignore all this, + // and just assume appropriate __sync_* routines are available on targets + // that don't have the appropriate native instructions. (In practice, + // such routines exist on Linux. We assume everyone else copies Linux.) MaxAtomicPromoteWidth = 64; - if (ShouldUseInlineAtomic) - MaxAtomicInlineWidth = 64; + MaxAtomicInlineWidth = 64; } } diff --git a/clang/test/CodeGen/arm-atomics-m0.c b/clang/test/CodeGen/arm-atomics-m0.c --- a/clang/test/CodeGen/arm-atomics-m0.c +++ b/clang/test/CodeGen/arm-atomics-m0.c @@ -11,14 +11,14 @@ void test_presence(void) { // CHECK-LABEL: @test_presence - // CHECK: __atomic_fetch_add_4 + // CHECK: atomicrmw add __atomic_fetch_add(&i, 1, memory_order_seq_cst); - // CHECK: __atomic_fetch_sub_4 + // CHECK: atomicrmw sub __atomic_fetch_sub(&i, 1, memory_order_seq_cst); - // CHECK: __atomic_load_4 + // CHECK: load atomic int r; __atomic_load(&i, &r, memory_order_seq_cst); - // CHECK: __atomic_store_4 + // CHECK: store atomic r = 0; __atomic_store(&i, &r, memory_order_seq_cst); diff --git a/clang/test/CodeGen/atomic-ops-libcall.c b/clang/test/CodeGen/atomic-ops-libcall.c --- a/clang/test/CodeGen/atomic-ops-libcall.c +++ b/clang/test/CodeGen/atomic-ops-libcall.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -no-opaque-pointers < %s -triple armv5e-none-linux-gnueabi -emit-llvm -O1 | FileCheck %s +// RUN: %clang_cc1 -no-opaque-pointers < %s -triple riscv32-none-linux-gnueabi -emit-llvm -O1 | FileCheck %s // FIXME: This file should not be checking -O1 output. // Ie, it is testing many IR optimizer passes as part of front-end verification. diff --git a/clang/test/CodeGen/atomics-inlining.c b/clang/test/CodeGen/atomics-inlining.c --- a/clang/test/CodeGen/atomics-inlining.c +++ b/clang/test/CodeGen/atomics-inlining.c @@ -37,16 +37,16 @@ (void)__atomic_store(&a1, &a2, memory_order_seq_cst); // ARM-LABEL: define{{.*}} void @test1 -// ARM: = call{{.*}} zeroext i8 @__atomic_load_1(ptr noundef @c1 -// ARM: call{{.*}} void @__atomic_store_1(ptr noundef @c1, i8 noundef zeroext -// ARM: = call{{.*}} zeroext i16 @__atomic_load_2(ptr noundef @s1 -// ARM: call{{.*}} void @__atomic_store_2(ptr noundef @s1, i16 noundef zeroext -// ARM: = call{{.*}} i32 @__atomic_load_4(ptr noundef @i1 -// ARM: call{{.*}} void @__atomic_store_4(ptr noundef @i1, i32 noundef -// ARM: = call{{.*}} i64 @__atomic_load_8(ptr noundef @ll1 -// ARM: call{{.*}} void @__atomic_store_8(ptr noundef @ll1, i64 noundef -// ARM: call{{.*}} void @__atomic_load(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 -// ARM: call{{.*}} void @__atomic_store(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 +// ARM: = load atomic i8, ptr @c1 seq_cst, align 1 +// ARM: store atomic i8 {{.*}}, ptr @c1 seq_cst, align 1 +// ARM: = load atomic i16, ptr @s1 seq_cst, align 2 +// ARM: store atomic i16 {{.*}}, ptr @s1 seq_cst, align 2 +// ARM: = load atomic i32, ptr @i1 seq_cst, align 4 +// ARM: store atomic i32 {{.*}}, ptr @i1 seq_cst, align 4 +// ARM: = load atomic i64, ptr @ll1 seq_cst, align 8 +// ARM: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 +// ARM: call void @__atomic_load(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 +// ARM: call void @__atomic_store(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 // PPC32-LABEL: define{{.*}} void @test1 // PPC32: = load atomic i8, ptr @c1 seq_cst, align 1 diff --git a/clang/test/CodeGen/c11atomics.c b/clang/test/CodeGen/c11atomics.c --- a/clang/test/CodeGen/c11atomics.c +++ b/clang/test/CodeGen/c11atomics.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -no-opaque-pointers %s -emit-llvm -o - -triple=armv5-unknown-freebsd -std=c11 | FileCheck %s +// RUN: %clang_cc1 -no-opaque-pointers %s -emit-llvm -o - -triple=riscv32-unknown-freebsd -std=c11 | FileCheck %s // Test that we are generating atomicrmw instructions, rather than // compare-exchange loops for common atomic ops. This makes a big difference @@ -73,7 +73,7 @@ // CHECK: testdec void testdec(void) { - // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b + // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b b--; // CHECK: atomicrmw sub i32* @i, i32 1 seq_cst, align 4 i--; @@ -81,7 +81,7 @@ l--; // CHECK: atomicrmw sub i16* @s, i16 1 seq_cst, align 2 s--; - // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b + // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b --b; // CHECK: atomicrmw sub i32* @i, i32 1 seq_cst, align 4 // CHECK: sub i32 @@ -96,7 +96,7 @@ // CHECK: testaddeq void testaddeq(void) { - // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b + // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b // CHECK: atomicrmw add i32* @i, i32 42 seq_cst, align 4 // CHECK: atomicrmw add i64* @l, i64 42 seq_cst, align 8 // CHECK: atomicrmw add i16* @s, i16 42 seq_cst, align 2 @@ -108,7 +108,7 @@ // CHECK: testsubeq void testsubeq(void) { - // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b + // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b // CHECK: atomicrmw sub i32* @i, i32 42 seq_cst, align 4 // CHECK: atomicrmw sub i64* @l, i64 42 seq_cst, align 8 // CHECK: atomicrmw sub i16* @s, i16 42 seq_cst, align 2 @@ -120,7 +120,7 @@ // CHECK: testxoreq void testxoreq(void) { - // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b + // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b // CHECK: atomicrmw xor i32* @i, i32 42 seq_cst, align 4 // CHECK: atomicrmw xor i64* @l, i64 42 seq_cst, align 8 // CHECK: atomicrmw xor i16* @s, i16 42 seq_cst, align 2 @@ -132,7 +132,7 @@ // CHECK: testoreq void testoreq(void) { - // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b + // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b // CHECK: atomicrmw or i32* @i, i32 42 seq_cst, align 4 // CHECK: atomicrmw or i64* @l, i64 42 seq_cst, align 8 // CHECK: atomicrmw or i16* @s, i16 42 seq_cst, align 2 @@ -144,7 +144,7 @@ // CHECK: testandeq void testandeq(void) { - // CHECK: call arm_aapcscc zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b + // CHECK: call zeroext i1 @__atomic_compare_exchange(i32 noundef 1, i8* noundef @b // CHECK: atomicrmw and i32* @i, i32 42 seq_cst, align 4 // CHECK: atomicrmw and i64* @l, i64 42 seq_cst, align 8 // CHECK: atomicrmw and i16* @s, i16 42 seq_cst, align 2 @@ -154,7 +154,7 @@ s &= 42; } -// CHECK-LABEL: define{{.*}} arm_aapcscc void @testFloat(float* +// CHECK-LABEL: define{{.*}} void @testFloat(float* void testFloat(_Atomic(float) *fp) { // CHECK: [[FP:%.*]] = alloca float* // CHECK-NEXT: [[X:%.*]] = alloca float @@ -173,7 +173,7 @@ // CHECK-NEXT: [[T0:%.*]] = load float*, float** [[FP]] // CHECK-NEXT: [[T1:%.*]] = bitcast float* [[T0]] to i8* // CHECK-NEXT: [[T2:%.*]] = bitcast float* [[TMP0]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 noundef 4, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_load(i32 noundef 4, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) // CHECK-NEXT: [[T3:%.*]] = load float, float* [[TMP0]], align 4 // CHECK-NEXT: store float [[T3]], float* [[F]] float f = *fp; @@ -183,13 +183,13 @@ // CHECK-NEXT: store float [[T0]], float* [[TMP1]], align 4 // CHECK-NEXT: [[T2:%.*]] = bitcast float* [[T1]] to i8* // CHECK-NEXT: [[T3:%.*]] = bitcast float* [[TMP1]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 noundef 4, i8* noundef [[T2]], i8* noundef [[T3]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_store(i32 noundef 4, i8* noundef [[T2]], i8* noundef [[T3]], i32 noundef 5) *fp = f; // CHECK-NEXT: ret void } -// CHECK: define{{.*}} arm_aapcscc void @testComplexFloat([[CF:{ float, float }]]* +// CHECK: define{{.*}} void @testComplexFloat([[CF:{ float, float }]]* void testComplexFloat(_Atomic(_Complex float) *fp) { // CHECK: [[FP:%.*]] = alloca [[CF]]*, align 4 // CHECK-NEXT: [[X:%.*]] = alloca [[CF]], align 8 @@ -214,7 +214,7 @@ // CHECK-NEXT: [[T0:%.*]] = load [[CF]]*, [[CF]]** [[FP]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[T0]] to i8* // CHECK-NEXT: [[T2:%.*]] = bitcast [[CF]]* [[TMP0]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]], [[CF]]* [[TMP0]], i32 0, i32 0 // CHECK-NEXT: [[R:%.*]] = load float, float* [[T0]] // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]], [[CF]]* [[TMP0]], i32 0, i32 1 @@ -236,7 +236,7 @@ // CHECK-NEXT: store float [[I]], float* [[T1]] // CHECK-NEXT: [[T0:%.*]] = bitcast [[CF]]* [[DEST]] to i8* // CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[TMP1]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 noundef 8, i8* noundef [[T0]], i8* noundef [[T1]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_store(i32 noundef 8, i8* noundef [[T0]], i8* noundef [[T1]], i32 noundef 5) *fp = f; // CHECK-NEXT: ret void @@ -244,7 +244,7 @@ typedef struct { short x, y, z, w; } S; _Atomic S testStructGlobal = (S){1, 2, 3, 4}; -// CHECK: define{{.*}} arm_aapcscc void @testStruct([[S:.*]]* +// CHECK: define{{.*}} void @testStruct([[S:.*]]* void testStruct(_Atomic(S) *fp) { // CHECK: [[FP:%.*]] = alloca [[S]]*, align 4 // CHECK-NEXT: [[X:%.*]] = alloca [[S]], align 8 @@ -276,7 +276,7 @@ // CHECK-NEXT: [[T0:%.*]] = load [[S]]*, [[S]]** [[FP]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[T0]] to i8* // CHECK-NEXT: [[T2:%.*]] = bitcast [[S]]* [[F]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) S f = *fp; // CHECK-NEXT: [[T0:%.*]] = load [[S]]*, [[S]]** [[FP]] @@ -285,7 +285,7 @@ // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 [[T1]], i8* align 2 [[T2]], i32 8, i1 false) // CHECK-NEXT: [[T3:%.*]] = bitcast [[S]]* [[T0]] to i8* // CHECK-NEXT: [[T4:%.*]] = bitcast [[S]]* [[TMP0]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 noundef 8, i8* noundef [[T3]], i8* noundef [[T4]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_store(i32 noundef 8, i8* noundef [[T3]], i8* noundef [[T4]], i32 noundef 5) *fp = f; // CHECK-NEXT: ret void @@ -293,7 +293,7 @@ typedef struct { short x, y, z; } PS; _Atomic PS testPromotedStructGlobal = (PS){1, 2, 3}; -// CHECK: define{{.*}} arm_aapcscc void @testPromotedStruct([[APS:.*]]* +// CHECK: define{{.*}} void @testPromotedStruct([[APS:.*]]* void testPromotedStruct(_Atomic(PS) *fp) { // CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4 // CHECK-NEXT: [[X:%.*]] = alloca [[APS]], align 8 @@ -331,7 +331,7 @@ // CHECK-NEXT: [[T0:%.*]] = load [[APS]]*, [[APS]]** [[FP]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i8* // CHECK-NEXT: [[T2:%.*]] = bitcast [[APS]]* [[TMP0]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]], [[APS]]* [[TMP0]], i32 0, i32 0 // CHECK-NEXT: [[T1:%.*]] = bitcast [[PS]]* [[F]] to i8* // CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T0]] to i8* @@ -347,13 +347,13 @@ // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 [[T2]], i8* align 2 [[T3]], i32 6, i1 false) // CHECK-NEXT: [[T4:%.*]] = bitcast [[APS]]* [[T0]] to i8* // CHECK-NEXT: [[T5:%.*]] = bitcast [[APS]]* [[TMP1]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 noundef 8, i8* noundef [[T4]], i8* noundef [[T5]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_store(i32 noundef 8, i8* noundef [[T4]], i8* noundef [[T5]], i32 noundef 5) *fp = f; // CHECK-NEXT: [[T0:%.*]] = load [[APS]]*, [[APS]]** [[FP]], align 4 // CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i8* // CHECK-NEXT: [[T2:%.*]] = bitcast [[APS]]* [[TMP3]] to i8* -// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) +// CHECK-NEXT: call void @__atomic_load(i32 noundef 8, i8* noundef [[T1]], i8* noundef [[T2]], i32 noundef 5) // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]], [[APS]]* [[TMP3]], i32 0, i32 0 // CHECK-NEXT: [[T1:%.*]] = bitcast %struct.PS* [[TMP2]] to i8* // CHECK-NEXT: [[T2:%.*]] = bitcast %struct.PS* [[T0]] to i8* @@ -368,7 +368,7 @@ } PS test_promoted_load(_Atomic(PS) *addr) { - // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret(%struct.PS) align 2 %agg.result, { %struct.PS, [2 x i8] }* noundef %addr) + // CHECK-LABEL: @test_promoted_load({ %struct.PS, [2 x i8] }* noundef %addr) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[ATOMIC_RES:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8 // CHECK: store { %struct.PS, [2 x i8] }* %addr, { %struct.PS, [2 x i8] }** [[ADDR_ARG]], align 4 @@ -376,10 +376,10 @@ // CHECK: [[ADDR64:%.*]] = bitcast { %struct.PS, [2 x i8] }* [[ADDR]] to i64* // CHECK: [[ATOMIC_RES64:%.*]] = bitcast { %struct.PS, [2 x i8] }* [[ATOMIC_RES]] to i64* // CHECK: [[ADDR8:%.*]] = bitcast i64* [[ADDR64]] to i8* - // CHECK: [[RES:%.*]] = call arm_aapcscc i64 @__atomic_load_8(i8* noundef [[ADDR8]], i32 noundef 5) + // CHECK: [[RES:%.*]] = call i64 @__atomic_load_8(i8* noundef [[ADDR8]], i32 noundef 5) // CHECK: store i64 [[RES]], i64* [[ATOMIC_RES64]], align 8 // CHECK: [[ATOMIC_RES_STRUCT:%.*]] = bitcast i64* [[ATOMIC_RES64]] to %struct.PS* - // CHECK: [[AGG_RESULT8:%.*]] = bitcast %struct.PS* %agg.result to i8* + // CHECK: [[AGG_RESULT8:%.*]] = bitcast %struct.PS* %retval to i8* // CHECK: [[ATOMIC_RES8:%.*]] = bitcast %struct.PS* [[ATOMIC_RES_STRUCT]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[AGG_RESULT8]], i8* align 8 [[ATOMIC_RES8]], i32 6, i1 false) @@ -406,12 +406,12 @@ // CHECK: [[ATOMIC_VAL64:%.*]] = bitcast { %struct.PS, [2 x i8] }* [[ATOMIC_VAL]] to i64* // CHECK: [[ADDR8:%.*]] = bitcast i64* [[ADDR64]] to i8* // CHECK: [[VAL64:%.*]] = load i64, i64* [[ATOMIC_VAL64]], align 2 - // CHECK: call arm_aapcscc void @__atomic_store_8(i8* noundef [[ADDR8]], i64 noundef [[VAL64]], i32 noundef 5) + // CHECK: call void @__atomic_store_8(i8* noundef [[ADDR8]], i64 noundef [[VAL64]], i32 noundef 5) __c11_atomic_store(addr, *val, 5); } PS test_promoted_exchange(_Atomic(PS) *addr, PS *val) { - // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret(%struct.PS) align 2 %agg.result, { %struct.PS, [2 x i8] }* noundef %addr, %struct.PS* noundef %val) + // CHECK-LABEL: @test_promoted_exchange({ %struct.PS, [2 x i8] }* noundef %addr, %struct.PS* noundef %val) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[VAL_ARG:%.*]] = alloca %struct.PS*, align 4 // CHECK: [[NONATOMIC_TMP:%.*]] = alloca %struct.PS, align 2 @@ -432,10 +432,10 @@ // CHECK: [[ATOMIC_RES64:%.*]] = bitcast { %struct.PS, [2 x i8] }* [[ATOMIC_RES]] to i64* // CHECK: [[ADDR8:%.*]] = bitcast i64* [[ADDR64]] to i8* // CHECK: [[VAL64:%.*]] = load i64, i64* [[ATOMIC_VAL64]], align 2 - // CHECK: [[RES:%.*]] = call arm_aapcscc i64 @__atomic_exchange_8(i8* noundef [[ADDR8]], i64 noundef [[VAL64]], i32 noundef 5) + // CHECK: [[RES:%.*]] = call i64 @__atomic_exchange_8(i8* noundef [[ADDR8]], i64 noundef [[VAL64]], i32 noundef 5) // CHECK: store i64 [[RES]], i64* [[ATOMIC_RES64]], align 8 // CHECK: [[ATOMIC_RES_STRUCT:%.*]] = bitcast i64* [[ATOMIC_RES64]] to %struct.PS* - // CHECK: [[AGG_RESULT8:%.*]] = bitcast %struct.PS* %agg.result to i8* + // CHECK: [[AGG_RESULT8:%.*]] = bitcast %struct.PS* %retval to i8* // CHECK: [[ATOMIC_RES8:%.*]] = bitcast %struct.PS* [[ATOMIC_RES_STRUCT]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 2 [[AGG_RESULT8]], i8* align 8 [[ATOMIC_RES8]], i32 6, i1 false) return __c11_atomic_exchange(addr, *val, 5); @@ -470,7 +470,7 @@ // CHECK: [[ADDR8:%.*]] = bitcast i64* [[ADDR64]] to i8* // CHECK: [[ATOMIC_DESIRED8:%.*]] = bitcast i64* [[ATOMIC_DESIRED64]] to i8* // CHECK: [[NEW64:%.*]] = load i64, i64* [[ATOMIC_NEW64]], align 2 - // CHECK: [[RES:%.*]] = call arm_aapcscc zeroext i1 @__atomic_compare_exchange_8(i8* noundef [[ADDR8]], i8* noundef [[ATOMIC_DESIRED8]], i64 noundef [[NEW64]], i32 noundef 5, i32 noundef 5) + // CHECK: [[RES:%.*]] = call zeroext i1 @__atomic_compare_exchange_8(i8* noundef [[ADDR8]], i8* noundef [[ATOMIC_DESIRED8]], i64 noundef [[NEW64]], i32 noundef 5, i32 noundef 5) // CHECK: ret i1 [[RES]] return __c11_atomic_compare_exchange_strong(addr, desired, *new, 5, 5); } @@ -479,12 +479,12 @@ struct Empty test_empty_struct_load(_Atomic(struct Empty)* empty) { // CHECK-LABEL: @test_empty_struct_load( - // CHECK: call arm_aapcscc zeroext i8 @__atomic_load_1(i8* noundef %{{.*}}, i32 noundef 5) + // CHECK: call zeroext i8 @__atomic_load_1(i8* noundef %{{.*}}, i32 noundef 5) return __c11_atomic_load(empty, 5); } void test_empty_struct_store(_Atomic(struct Empty)* empty, struct Empty value) { // CHECK-LABEL: @test_empty_struct_store( - // CHECK: call arm_aapcscc void @__atomic_store_1(i8* noundef %{{.*}}, i8 noundef zeroext %{{.*}}, i32 noundef 5) + // CHECK: call void @__atomic_store_1(i8* noundef %{{.*}}, i8 noundef zeroext %{{.*}}, i32 noundef 5) __c11_atomic_store(empty, value, 5); } diff --git a/clang/test/CodeGen/pr45476.cpp b/clang/test/CodeGen/pr45476.cpp --- a/clang/test/CodeGen/pr45476.cpp +++ b/clang/test/CodeGen/pr45476.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple arm-unknown-linux-gnueabi -emit-llvm %s -o - | FileCheck -check-prefix=LIBCALL %s +// RUN: %clang_cc1 -triple riscv32-unknown-linux-gnueabi -emit-llvm %s -o - | FileCheck -check-prefix=LIBCALL %s // RUN: %clang_cc1 -triple armv8-eabi -emit-llvm %s -o - | FileCheck -check-prefix=NATIVE %s // PR45476 diff --git a/clang/test/CodeGenCXX/threadsafe-statics-no-atomic.cpp b/clang/test/CodeGenCXX/threadsafe-statics-no-atomic.cpp --- a/clang/test/CodeGenCXX/threadsafe-statics-no-atomic.cpp +++ b/clang/test/CodeGenCXX/threadsafe-statics-no-atomic.cpp @@ -1,5 +1,5 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py -// RUN: %clang_cc1 -emit-llvm -triple=thumbv6m-eabi -o - %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -triple=riscv32 -o - %s | FileCheck %s int f(); diff --git a/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl b/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl --- a/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl +++ b/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -no-opaque-pointers < %s -cl-std=CL2.0 -triple spir64 -emit-llvm | FileCheck -check-prefix=SPIR %s -// RUN: %clang_cc1 -no-opaque-pointers < %s -cl-std=CL2.0 -triple armv5e-none-linux-gnueabi -emit-llvm | FileCheck -check-prefix=ARM %s +// RUN: %clang_cc1 -no-opaque-pointers < %s -cl-std=CL2.0 -triple riscv32-none-linux-gnueabi -emit-llvm | FileCheck -check-prefix=ARM %s typedef enum memory_order { memory_order_relaxed = __ATOMIC_RELAXED, memory_order_acquire = __ATOMIC_ACQUIRE, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -1357,27 +1357,20 @@ } // Compute supported atomic widths. - if (Subtarget->isTargetLinux() || - (!Subtarget->isMClass() && Subtarget->hasV6Ops())) { - // For targets where __sync_* routines are reliably available, we use them - // if necessary. - // - // ARM Linux always supports 64-bit atomics through kernel-assisted atomic - // routines (kernel 3.1 or later). FIXME: Not with compiler-rt? + if (Subtarget->isMClass()) { + // Cortex-M besides Cortex-M0 has 32-bit atomics. // - // ARMv6 targets have native instructions in ARM mode. For Thumb mode, - // such targets should provide __sync_* routines, which use the ARM mode - // instructions. (ARMv6 doesn't have dmb, but it has an equivalent - // encoding; see ARMISD::MEMBARRIER_MCR.) - setMaxAtomicSizeInBitsSupported(64); - } else if ((Subtarget->isMClass() && Subtarget->hasV8MBaselineOps()) || - Subtarget->hasForced32BitAtomics()) { - // Cortex-M (besides Cortex-M0) have 32-bit atomics. + // Cortex-M0 is missing ldrex/strex, so we generate __sync_* calls. + // We assume the user somehow makes that lock-free. setMaxAtomicSizeInBitsSupported(32); } else { - // We can't assume anything about other targets; just use libatomic - // routines. - setMaxAtomicSizeInBitsSupported(0); + // v7 has 64-bit atomics. Some v6 variants have 64-bit atomics, some + // have 32-bit atomics. Older variants have no atomics, but they + // might be emulated on some targets. We completely ignore all this, + // and just assume appropriate __sync_* routines are available on targets + // that don't have the appropriate native instructions. (In practice, + // such routines exist on Linux. We assume everyone else copies Linux.) + setMaxAtomicSizeInBitsSupported(64); } setMaxDivRemBitWidthSupported(64); diff --git a/llvm/test/CodeGen/ARM/atomic-64bit.ll b/llvm/test/CodeGen/ARM/atomic-64bit.ll --- a/llvm/test/CodeGen/ARM/atomic-64bit.ll +++ b/llvm/test/CodeGen/ARM/atomic-64bit.ll @@ -3,7 +3,7 @@ ; RUN: llc < %s -mtriple=armebv7 -target-abi apcs | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE ; RUN: llc < %s -mtriple=thumbebv7-none-linux-gnueabihf | FileCheck %s --check-prefix=CHECK-THUMB --check-prefix=CHECK-THUMB-BE ; RUN: llc < %s -mtriple=armv7m--none-eabi | FileCheck %s --check-prefix=CHECK-M -; RUN: llc < %s -mtriple=armv8m--none-eabi | FileCheck %s --check-prefix=CHECK-M +; RUN: llc < %s -mtriple=armv8m.base--none-eabi | FileCheck %s --check-prefix=CHECK-M define i64 @test1(i64* %ptr, i64 %val) { ; CHECK-LABEL: test1: diff --git a/llvm/test/CodeGen/ARM/atomic-load-store.ll b/llvm/test/CodeGen/ARM/atomic-load-store.ll --- a/llvm/test/CodeGen/ARM/atomic-load-store.ll +++ b/llvm/test/CodeGen/ARM/atomic-load-store.ll @@ -38,8 +38,7 @@ ; ARMV4-LABEL: test1: ; ARMV4: @ %bb.0: ; ARMV4-NEXT: push {r11, lr} -; ARMV4-NEXT: mov r2, #5 -; ARMV4-NEXT: bl __atomic_store_4 +; ARMV4-NEXT: bl __sync_lock_test_and_set_4 ; ARMV4-NEXT: pop {r11, lr} ; ARMV4-NEXT: mov pc, lr ; @@ -91,8 +90,9 @@ ; ARMV4-LABEL: test2: ; ARMV4: @ %bb.0: ; ARMV4-NEXT: push {r11, lr} -; ARMV4-NEXT: mov r1, #5 -; ARMV4-NEXT: bl __atomic_load_4 +; ARMV4-NEXT: mov r1, #0 +; ARMV4-NEXT: mov r2, #0 +; ARMV4-NEXT: bl __sync_val_compare_and_swap_4 ; ARMV4-NEXT: pop {r11, lr} ; ARMV4-NEXT: mov pc, lr ; @@ -139,15 +139,8 @@ ; ; ARMV4-LABEL: test3: ; ARMV4: @ %bb.0: -; ARMV4-NEXT: push {r4, lr} -; ARMV4-NEXT: mov r4, r1 -; ARMV4-NEXT: mov r1, #0 -; ARMV4-NEXT: bl __atomic_load_1 -; ARMV4-NEXT: mov r1, r0 -; ARMV4-NEXT: mov r0, r4 -; ARMV4-NEXT: mov r2, #0 -; ARMV4-NEXT: bl __atomic_store_1 -; ARMV4-NEXT: pop {r4, lr} +; ARMV4-NEXT: ldrb r0, [r0] +; ARMV4-NEXT: strb r0, [r1] ; ARMV4-NEXT: mov pc, lr ; ; ARMV6-LABEL: test3: @@ -212,12 +205,12 @@ ; ARMV4: @ %bb.0: ; ARMV4-NEXT: push {r4, lr} ; ARMV4-NEXT: mov r4, r1 -; ARMV4-NEXT: mov r1, #5 -; ARMV4-NEXT: bl __atomic_load_1 +; ARMV4-NEXT: mov r1, #0 +; ARMV4-NEXT: mov r2, #0 +; ARMV4-NEXT: bl __sync_val_compare_and_swap_1 ; ARMV4-NEXT: mov r1, r0 ; ARMV4-NEXT: mov r0, r4 -; ARMV4-NEXT: mov r2, #5 -; ARMV4-NEXT: bl __atomic_store_1 +; ARMV4-NEXT: bl __sync_lock_test_and_set_1 ; ARMV4-NEXT: pop {r4, lr} ; ARMV4-NEXT: mov pc, lr ; @@ -283,8 +276,14 @@ ; ARMV4-LABEL: test_old_load_64bit: ; ARMV4: @ %bb.0: ; ARMV4-NEXT: push {r11, lr} -; ARMV4-NEXT: mov r1, #5 -; ARMV4-NEXT: bl __atomic_load_8 +; ARMV4-NEXT: sub sp, sp, #8 +; ARMV4-NEXT: mov r1, #0 +; ARMV4-NEXT: mov r2, #0 +; ARMV4-NEXT: mov r3, #0 +; ARMV4-NEXT: str r1, [sp] +; ARMV4-NEXT: str r1, [sp, #4] +; ARMV4-NEXT: bl __sync_val_compare_and_swap_8 +; ARMV4-NEXT: add sp, sp, #8 ; ARMV4-NEXT: pop {r11, lr} ; ARMV4-NEXT: mov pc, lr ; @@ -401,11 +400,7 @@ ; ARMV4-LABEL: test_old_store_64bit: ; ARMV4: @ %bb.0: ; ARMV4-NEXT: push {r11, lr} -; ARMV4-NEXT: sub sp, sp, #8 -; ARMV4-NEXT: mov r1, #5 -; ARMV4-NEXT: str r1, [sp] -; ARMV4-NEXT: bl __atomic_store_8 -; ARMV4-NEXT: add sp, sp, #8 +; ARMV4-NEXT: bl __sync_lock_test_and_set_8 ; ARMV4-NEXT: pop {r11, lr} ; ARMV4-NEXT: mov pc, lr ; diff --git a/llvm/test/CodeGen/ARM/atomic-op.ll b/llvm/test/CodeGen/ARM/atomic-op.ll --- a/llvm/test/CodeGen/ARM/atomic-op.ll +++ b/llvm/test/CodeGen/ARM/atomic-op.ll @@ -1,12 +1,12 @@ -; RUN: llc < %s -mtriple=armv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix CHECK-ARMV7 -; RUN: llc < %s -mtriple=thumbv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-T2 -; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-T1 -; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs -mcpu=cortex-m0 | FileCheck %s --check-prefix=CHECK-T1-M0 -; RUN: llc < %s -mtriple=thumbv7--none-eabi -thread-model single -verify-machineinstrs | FileCheck %s --check-prefix=CHECK-BAREMETAL +; RUN: llc < %s -mtriple=armv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefixes=CHECKALL,CHECK,CHECK-ARMV7 +; RUN: llc < %s -mtriple=thumbv7-apple-ios -verify-machineinstrs | FileCheck %s --check-prefixes=CHECKALL,CHECK,CHECK-T2 +; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs | FileCheck %s --check-prefixes=CHECKALL,CHECK-T1 +; RUN: llc < %s -mtriple=thumbv6-apple-ios -verify-machineinstrs -mcpu=cortex-m0 | FileCheck %s --check-prefixes=CHECKALL,CHECK-T1-M0 +; RUN: llc < %s -mtriple=thumbv7--none-eabi -thread-model single -verify-machineinstrs | FileCheck %s --check-prefixes=CHECKALL,CHECK-BAREMETAL target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" -; CHECK-LABEL: _func: +; CHECKALL-LABEL: func: define void @func(i32 %argc, i8** %argv) nounwind { entry: %argc.addr = alloca i32 ; [#uses=1] @@ -32,7 +32,7 @@ ; CHECK: add ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_add_4 - ; CHECK-T1-M0: bl ___atomic_fetch_add_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_add_4 ; CHECK-BAREMETAL: add ; CHECK-BAREMETAL-NOT: __sync %0 = atomicrmw add i32* %val1, i32 %tmp monotonic @@ -42,7 +42,7 @@ ; CHECK: sub ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_sub_4 - ; CHECK-T1-M0: bl ___atomic_fetch_sub_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_sub_4 ; CHECK-BAREMETAL: sub ; CHECK-BAREMETAL-NOT: __sync %1 = atomicrmw sub i32* %val2, i32 30 monotonic @@ -52,7 +52,7 @@ ; CHECK: add ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_add_4 - ; CHECK-T1-M0: bl ___atomic_fetch_add_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_add_4 ; CHECK-BAREMETAL: add ; CHECK-BAREMETAL-NOT: __sync %2 = atomicrmw add i32* %val2, i32 1 monotonic @@ -62,7 +62,7 @@ ; CHECK: sub ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_sub_4 - ; CHECK-T1-M0: bl ___atomic_fetch_sub_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_sub_4 ; CHECK-BAREMETAL: sub ; CHECK-BAREMETAL-NOT: __sync %3 = atomicrmw sub i32* %val2, i32 1 monotonic @@ -72,7 +72,7 @@ ; CHECK: and ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_and_4 - ; CHECK-T1-M0: bl ___atomic_fetch_and_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_and_4 ; CHECK-BAREMETAL: and ; CHECK-BAREMETAL-NOT: __sync %4 = atomicrmw and i32* %andt, i32 4080 monotonic @@ -82,7 +82,7 @@ ; CHECK: or ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_or_4 - ; CHECK-T1-M0: bl ___atomic_fetch_or_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_or_4 ; CHECK-BAREMETAL: or ; CHECK-BAREMETAL-NOT: __sync %5 = atomicrmw or i32* %ort, i32 4080 monotonic @@ -92,7 +92,7 @@ ; CHECK: eor ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_xor_4 - ; CHECK-T1-M0: bl ___atomic_fetch_xor_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_xor_4 ; CHECK-BAREMETAL: eor ; CHECK-BAREMETAL-NOT: __sync %6 = atomicrmw xor i32* %xort, i32 4080 monotonic @@ -102,8 +102,7 @@ ; CHECK: cmp ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_min_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_min_4 ; CHECK-BAREMETAL-NOT: __sync %7 = atomicrmw min i32* %val2, i32 16 monotonic store i32 %7, i32* %old @@ -113,8 +112,7 @@ ; CHECK: cmp ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_min_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_min_4 ; CHECK-BAREMETAL-NOT: __sync %8 = atomicrmw min i32* %val2, i32 %neg monotonic store i32 %8, i32* %old @@ -123,8 +121,7 @@ ; CHECK: cmp ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_max_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_max_4 ; CHECK-BAREMETAL-NOT: __sync %9 = atomicrmw max i32* %val2, i32 1 monotonic store i32 %9, i32* %old @@ -134,7 +131,7 @@ ; CHECK-NOT: cmp ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_max_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 + ; CHECK-T1-M0: bl ___sync_fetch_and_max_4 ; CHECK-BAREMETAL: bic ; CHECK-BAREMETAL-NOT: __sync %10 = atomicrmw max i32* %val2, i32 0 monotonic @@ -144,8 +141,7 @@ ; CHECK: cmp ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_umin_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umin_4 ; CHECK-BAREMETAL-NOT: __sync %11 = atomicrmw umin i32* %val2, i32 16 monotonic store i32 %11, i32* %old @@ -155,8 +151,7 @@ ; CHECK: cmp ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_umin_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umin_4 ; CHECK-BAREMETAL-NOT: __sync %12 = atomicrmw umin i32* %val2, i32 %uneg monotonic store i32 %12, i32* %old @@ -165,8 +160,7 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umax_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umax_4 ; CHECK-BAREMETAL-NOT: __sync %13 = atomicrmw umax i32* %val2, i32 1 monotonic store i32 %13, i32* %old @@ -175,8 +169,7 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umax_4 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_4 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umax_4 ; CHECK-BAREMETAL-NOT: __sync %14 = atomicrmw umax i32* %val2, i32 0 monotonic store i32 %14, i32* %old @@ -184,7 +177,7 @@ ret void } -; CHECK-LABEL: _func2: +; CHECKALL-LABEL: func2: define void @func2() nounwind { entry: %val = alloca i16 @@ -194,8 +187,7 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umin_2 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umin_2 ; CHECK-BAREMETAL-NOT: __sync %0 = atomicrmw umin i16* %val, i16 16 monotonic store i16 %0, i16* %old @@ -204,8 +196,7 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umin_2 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umin_2 ; CHECK-BAREMETAL-NOT: __sync %1 = atomicrmw umin i16* %val, i16 %uneg monotonic store i16 %1, i16* %old @@ -213,8 +204,7 @@ ; CHECK: cmp ; CHECK: strex ; CHECK-T1: bl ___sync_fetch_and_umax_2 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umax_2 ; CHECK-BAREMETAL-NOT: __sync %2 = atomicrmw umax i16* %val, i16 1 monotonic store i16 %2, i16* %old @@ -222,15 +212,14 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umax_2 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_2 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umax_2 ; CHECK-BAREMETAL-NOT: __sync %3 = atomicrmw umax i16* %val, i16 0 monotonic store i16 %3, i16* %old ret void } -; CHECK-LABEL: _func3: +; CHECKALL-LABEL: func3: define void @func3() nounwind { entry: %val = alloca i8 @@ -240,8 +229,7 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umin_1 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umin_1 ; CHECK-BAREMETAL-NOT: __sync %0 = atomicrmw umin i8* %val, i8 16 monotonic store i8 %0, i8* %old @@ -249,8 +237,7 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umin_1 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umin_1 ; CHECK-BAREMETAL-NOT: __sync %uneg = sub i8 0, 1 %1 = atomicrmw umin i8* %val, i8 %uneg monotonic @@ -259,8 +246,7 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umax_1 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umax_1 ; CHECK-BAREMETAL-NOT: __sync %2 = atomicrmw umax i8* %val, i8 1 monotonic store i8 %2, i8* %old @@ -268,15 +254,14 @@ ; CHECK: strex ; CHECK: cmp ; CHECK-T1: bl ___sync_fetch_and_umax_1 - ; CHECK-T1-M0: bl ___atomic_compare_exchange_1 - ; CHECK-BAREMETAL: cmp + ; CHECK-T1-M0: bl ___sync_fetch_and_umax_1 ; CHECK-BAREMETAL-NOT: __sync %3 = atomicrmw umax i8* %val, i8 0 monotonic store i8 %3, i8* %old ret void } -; CHECK-LABEL: _func4: +; CHECKALL-LABEL: func4: ; This function should not need to use callee-saved registers. ; rdar://problem/12203728 ; CHECK-NOT: r4 @@ -287,7 +272,7 @@ } define i32 @test_cmpxchg_fail_order(i32 *%addr, i32 %desired, i32 %new) { -; CHECK-LABEL: test_cmpxchg_fail_order: +; CHECKALL-LABEL: test_cmpxchg_fail_order: %pair = cmpxchg i32* %addr, i32 %desired, i32 %new seq_cst monotonic %oldval = extractvalue { i32, i1 } %pair, 0 @@ -329,7 +314,7 @@ } define i32 @test_cmpxchg_fail_order1(i32 *%addr, i32 %desired, i32 %new) { -; CHECK-LABEL: test_cmpxchg_fail_order1: +; CHECKALL-LABEL: test_cmpxchg_fail_order1: %pair = cmpxchg i32* %addr, i32 %desired, i32 %new acquire acquire %oldval = extractvalue { i32, i1 } %pair, 0 @@ -352,7 +337,7 @@ } define i32 @load_load_add_acquire(i32* %mem1, i32* %mem2) nounwind { -; CHECK-LABEL: load_load_add_acquire +; CHECKALL-LABEL: load_load_add_acquire %val1 = load atomic i32, i32* %mem1 acquire, align 4 %val2 = load atomic i32, i32* %mem2 acquire, align 4 %tmp = add i32 %val1, %val2 @@ -363,23 +348,26 @@ ; CHECK: dmb ; CHECK: add r0, -; CHECK-T1-M0: __atomic_load_4 -; CHECK-T1-M0: __atomic_load_4 +; CHECK-T1-M0: ldr {{r[0-9]}}, [r0] +; CHECK-T1-M0: dmb +; CHECK-T1-M0: ldr {{r[0-9]}}, [r1] +; CHECK-T1-M0: adds r0, +; CHECK-T1-M0: dmb ; CHECK-T1: ___sync_val_compare_and_swap_4 ; CHECK-T1: ___sync_val_compare_and_swap_4 -; CHECK-BAREMETAL: ldr {{r[0-9]}}, [r0] -; CHECK-BAREMETAL-NOT: dmb ; CHECK-BAREMETAL: ldr {{r[0-9]}}, [r1] ; CHECK-BAREMETAL-NOT: dmb +; CHECK-BAREMETAL: ldr {{r[0-9]}}, [r0] +; CHECK-BAREMETAL-NOT: dmb ; CHECK-BAREMETAL: add r0, ret i32 %tmp } define void @store_store_release(i32* %mem1, i32 %val1, i32* %mem2, i32 %val2) { -; CHECK-LABEL: store_store_release +; CHECKALL-LABEL: store_store_release store atomic i32 %val1, i32* %mem1 release, align 4 store atomic i32 %val2, i32* %mem2 release, align 4 @@ -391,8 +379,10 @@ ; CHECK-T1: ___sync_lock_test_and_set ; CHECK-T1: ___sync_lock_test_and_set -; CHECK-T1-M0: __atomic_store_4 -; CHECK-T1-M0: __atomic_store_4 +; CHECK-T1-M0: dmb +; CHECK-T1-M0: str r1, [r0] +; CHECK-T1-M0: dmb +; CHECK-T1-M0: str r3, [r2] ; CHECK-BAREMETAL-NOT: dmb ; CHECK-BAREMETAL: str r1, [r0] @@ -403,7 +393,7 @@ } define void @load_fence_store_monotonic(i32* %mem1, i32* %mem2) { -; CHECK-LABEL: load_fence_store_monotonic +; CHECKALL-LABEL: load_fence_store_monotonic %val = load atomic i32, i32* %mem1 monotonic, align 4 fence seq_cst store atomic i32 %val, i32* %mem2 monotonic, align 4 @@ -412,9 +402,9 @@ ; CHECK: dmb ; CHECK: str [[R0]], [r1] -; CHECK-T1-M0: __atomic_load_4 +; CHECK-T1-M0: ldr [[R0:r[0-9]]], [{{r[0-9]+}}] ; CHECK-T1-M0: dmb -; CHECK-T1-M0: __atomic_store_4 +; CHECK-T1-M0: str [[R0]], [{{r[0-9]+}}] ; CHECK-T1: ldr [[R0:r[0-9]]], [{{r[0-9]+}}] ; CHECK-T1: {{dmb|bl ___sync_synchronize}} diff --git a/llvm/test/CodeGen/ARM/thumbv6m-atomic32.ll b/llvm/test/CodeGen/ARM/thumbv6m-atomic32.ll --- a/llvm/test/CodeGen/ARM/thumbv6m-atomic32.ll +++ b/llvm/test/CodeGen/ARM/thumbv6m-atomic32.ll @@ -3,285 +3,156 @@ ; RUN: llc -mtriple=thumbv6m-none-eabi -mattr=+atomics-32 < %s | FileCheck %s --check-prefixes=CHECK,ATOMIC32 define i8 @load8(ptr %p) { -; NO-ATOMIC32-LABEL: load8: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #5 -; NO-ATOMIC32-NEXT: bl __atomic_load_1 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: load8: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: ldrb r0, [r0] -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: bx lr +; CHECK-LABEL: load8: +; CHECK: @ %bb.0: +; CHECK-NEXT: ldrb r0, [r0] +; CHECK-NEXT: dmb sy +; CHECK-NEXT: bx lr %v = load atomic i8, ptr %p seq_cst, align 1 ret i8 %v } define void @store8(ptr %p) { -; NO-ATOMIC32-LABEL: store8: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #0 -; NO-ATOMIC32-NEXT: movs r2, #5 -; NO-ATOMIC32-NEXT: bl __atomic_store_1 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: store8: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #0 -; ATOMIC32-NEXT: strb r1, [r0] -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: bx lr +; CHECK-LABEL: store8: +; CHECK: @ %bb.0: +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #0 +; CHECK-NEXT: strb r1, [r0] +; CHECK-NEXT: dmb sy +; CHECK-NEXT: bx lr store atomic i8 0, ptr %p seq_cst, align 1 ret void } define i8 @rmw8(ptr %p) { -; NO-ATOMIC32-LABEL: rmw8: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #1 -; NO-ATOMIC32-NEXT: movs r2, #5 -; NO-ATOMIC32-NEXT: bl __atomic_fetch_add_1 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: rmw8: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: .save {r7, lr} -; ATOMIC32-NEXT: push {r7, lr} -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #1 -; ATOMIC32-NEXT: bl __sync_fetch_and_add_1 -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: pop {r7, pc} +; CHECK-LABEL: rmw8: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #1 +; CHECK-NEXT: bl __sync_fetch_and_add_1 +; CHECK-NEXT: dmb sy +; CHECK-NEXT: pop {r7, pc} %v = atomicrmw add ptr %p, i8 1 seq_cst, align 1 ret i8 %v } define i8 @cmpxchg8(ptr %p) { -; NO-ATOMIC32-LABEL: cmpxchg8: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: .pad #8 -; NO-ATOMIC32-NEXT: sub sp, #8 -; NO-ATOMIC32-NEXT: add r1, sp, #4 -; NO-ATOMIC32-NEXT: movs r2, #0 -; NO-ATOMIC32-NEXT: strb r2, [r1] -; NO-ATOMIC32-NEXT: movs r3, #5 -; NO-ATOMIC32-NEXT: str r3, [sp] -; NO-ATOMIC32-NEXT: movs r2, #1 -; NO-ATOMIC32-NEXT: bl __atomic_compare_exchange_1 -; NO-ATOMIC32-NEXT: ldr r0, [sp, #4] -; NO-ATOMIC32-NEXT: add sp, #8 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: cmpxchg8: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: .save {r7, lr} -; ATOMIC32-NEXT: push {r7, lr} -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #0 -; ATOMIC32-NEXT: movs r2, #1 -; ATOMIC32-NEXT: bl __sync_val_compare_and_swap_1 -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: pop {r7, pc} +; CHECK-LABEL: cmpxchg8: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #0 +; CHECK-NEXT: movs r2, #1 +; CHECK-NEXT: bl __sync_val_compare_and_swap_1 +; CHECK-NEXT: dmb sy +; CHECK-NEXT: pop {r7, pc} %res = cmpxchg ptr %p, i8 0, i8 1 seq_cst seq_cst %res.0 = extractvalue { i8, i1 } %res, 0 ret i8 %res.0 } define i16 @load16(ptr %p) { -; NO-ATOMIC32-LABEL: load16: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #5 -; NO-ATOMIC32-NEXT: bl __atomic_load_2 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: load16: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: ldrh r0, [r0] -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: bx lr +; CHECK-LABEL: load16: +; CHECK: @ %bb.0: +; CHECK-NEXT: ldrh r0, [r0] +; CHECK-NEXT: dmb sy +; CHECK-NEXT: bx lr %v = load atomic i16, ptr %p seq_cst, align 2 ret i16 %v } define void @store16(ptr %p) { -; NO-ATOMIC32-LABEL: store16: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #0 -; NO-ATOMIC32-NEXT: movs r2, #5 -; NO-ATOMIC32-NEXT: bl __atomic_store_2 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: store16: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #0 -; ATOMIC32-NEXT: strh r1, [r0] -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: bx lr +; CHECK-LABEL: store16: +; CHECK: @ %bb.0: +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #0 +; CHECK-NEXT: strh r1, [r0] +; CHECK-NEXT: dmb sy +; CHECK-NEXT: bx lr store atomic i16 0, ptr %p seq_cst, align 2 ret void } define i16 @rmw16(ptr %p) { -; NO-ATOMIC32-LABEL: rmw16: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #1 -; NO-ATOMIC32-NEXT: movs r2, #5 -; NO-ATOMIC32-NEXT: bl __atomic_fetch_add_2 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: rmw16: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: .save {r7, lr} -; ATOMIC32-NEXT: push {r7, lr} -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #1 -; ATOMIC32-NEXT: bl __sync_fetch_and_add_2 -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: pop {r7, pc} +; CHECK-LABEL: rmw16: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #1 +; CHECK-NEXT: bl __sync_fetch_and_add_2 +; CHECK-NEXT: dmb sy +; CHECK-NEXT: pop {r7, pc} %v = atomicrmw add ptr %p, i16 1 seq_cst, align 2 ret i16 %v } define i16 @cmpxchg16(ptr %p) { -; NO-ATOMIC32-LABEL: cmpxchg16: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: .pad #8 -; NO-ATOMIC32-NEXT: sub sp, #8 -; NO-ATOMIC32-NEXT: add r1, sp, #4 -; NO-ATOMIC32-NEXT: movs r2, #0 -; NO-ATOMIC32-NEXT: strh r2, [r1] -; NO-ATOMIC32-NEXT: movs r3, #5 -; NO-ATOMIC32-NEXT: str r3, [sp] -; NO-ATOMIC32-NEXT: movs r2, #1 -; NO-ATOMIC32-NEXT: bl __atomic_compare_exchange_2 -; NO-ATOMIC32-NEXT: ldr r0, [sp, #4] -; NO-ATOMIC32-NEXT: add sp, #8 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: cmpxchg16: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: .save {r7, lr} -; ATOMIC32-NEXT: push {r7, lr} -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #0 -; ATOMIC32-NEXT: movs r2, #1 -; ATOMIC32-NEXT: bl __sync_val_compare_and_swap_2 -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: pop {r7, pc} +; CHECK-LABEL: cmpxchg16: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #0 +; CHECK-NEXT: movs r2, #1 +; CHECK-NEXT: bl __sync_val_compare_and_swap_2 +; CHECK-NEXT: dmb sy +; CHECK-NEXT: pop {r7, pc} %res = cmpxchg ptr %p, i16 0, i16 1 seq_cst seq_cst %res.0 = extractvalue { i16, i1 } %res, 0 ret i16 %res.0 } define i32 @load32(ptr %p) { -; NO-ATOMIC32-LABEL: load32: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #5 -; NO-ATOMIC32-NEXT: bl __atomic_load_4 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: load32: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: ldr r0, [r0] -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: bx lr +; CHECK-LABEL: load32: +; CHECK: @ %bb.0: +; CHECK-NEXT: ldr r0, [r0] +; CHECK-NEXT: dmb sy +; CHECK-NEXT: bx lr %v = load atomic i32, ptr %p seq_cst, align 4 ret i32 %v } define void @store32(ptr %p) { -; NO-ATOMIC32-LABEL: store32: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #0 -; NO-ATOMIC32-NEXT: movs r2, #5 -; NO-ATOMIC32-NEXT: bl __atomic_store_4 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: store32: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #0 -; ATOMIC32-NEXT: str r1, [r0] -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: bx lr +; CHECK-LABEL: store32: +; CHECK: @ %bb.0: +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #0 +; CHECK-NEXT: str r1, [r0] +; CHECK-NEXT: dmb sy +; CHECK-NEXT: bx lr store atomic i32 0, ptr %p seq_cst, align 4 ret void } define i32 @rmw32(ptr %p) { -; NO-ATOMIC32-LABEL: rmw32: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: movs r1, #1 -; NO-ATOMIC32-NEXT: movs r2, #5 -; NO-ATOMIC32-NEXT: bl __atomic_fetch_add_4 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: rmw32: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: .save {r7, lr} -; ATOMIC32-NEXT: push {r7, lr} -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #1 -; ATOMIC32-NEXT: bl __sync_fetch_and_add_4 -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: pop {r7, pc} +; CHECK-LABEL: rmw32: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #1 +; CHECK-NEXT: bl __sync_fetch_and_add_4 +; CHECK-NEXT: dmb sy +; CHECK-NEXT: pop {r7, pc} %v = atomicrmw add ptr %p, i32 1 seq_cst, align 4 ret i32 %v } define i32 @cmpxchg32(ptr %p) { -; NO-ATOMIC32-LABEL: cmpxchg32: -; NO-ATOMIC32: @ %bb.0: -; NO-ATOMIC32-NEXT: .save {r7, lr} -; NO-ATOMIC32-NEXT: push {r7, lr} -; NO-ATOMIC32-NEXT: .pad #8 -; NO-ATOMIC32-NEXT: sub sp, #8 -; NO-ATOMIC32-NEXT: movs r1, #0 -; NO-ATOMIC32-NEXT: str r1, [sp, #4] -; NO-ATOMIC32-NEXT: movs r3, #5 -; NO-ATOMIC32-NEXT: str r3, [sp] -; NO-ATOMIC32-NEXT: add r1, sp, #4 -; NO-ATOMIC32-NEXT: movs r2, #1 -; NO-ATOMIC32-NEXT: bl __atomic_compare_exchange_4 -; NO-ATOMIC32-NEXT: ldr r0, [sp, #4] -; NO-ATOMIC32-NEXT: add sp, #8 -; NO-ATOMIC32-NEXT: pop {r7, pc} -; -; ATOMIC32-LABEL: cmpxchg32: -; ATOMIC32: @ %bb.0: -; ATOMIC32-NEXT: .save {r7, lr} -; ATOMIC32-NEXT: push {r7, lr} -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: movs r1, #0 -; ATOMIC32-NEXT: movs r2, #1 -; ATOMIC32-NEXT: bl __sync_val_compare_and_swap_4 -; ATOMIC32-NEXT: dmb sy -; ATOMIC32-NEXT: pop {r7, pc} +; CHECK-LABEL: cmpxchg32: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: dmb sy +; CHECK-NEXT: movs r1, #0 +; CHECK-NEXT: movs r2, #1 +; CHECK-NEXT: bl __sync_val_compare_and_swap_4 +; CHECK-NEXT: dmb sy +; CHECK-NEXT: pop {r7, pc} %res = cmpxchg ptr %p, i32 0, i32 1 seq_cst seq_cst %res.0 = extractvalue { i32, i1 } %res, 0 ret i32 %res.0 @@ -359,3 +230,6 @@ %res.0 = extractvalue { i64, i1 } %res, 0 ret i64 %res.0 } +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; ATOMIC32: {{.*}} +; NO-ATOMIC32: {{.*}}