1 // RUN: %clang_cc1 -triple x86_64 -emit-llvm %s \ 2 // RUN: -o - | FileCheck -check-prefixes=CHECK,NATIVE %s 3 // RUN: %clang_cc1 -triple riscv32 -target-feature -a -emit-llvm %s \ 4 // RUN: -o - | FileCheck -check-prefixes=CHECK,LIBCALL %s 5 6 void foo(int x) 7 { 8 _Atomic(int) i = 0; 9 _Atomic(short) j = 0; 10 // Check that multiply / divides on atomics produce a cmpxchg loop 11 i *= 2; 12 // NATIVE: mul nsw i32 13 // NATIVE: cmpxchg i32* {{.*}} seq_cst, align 4 14 // LIBCALL: mul nsw i32 15 // LIBCALL: i1 @__atomic_compare_exchange(i32 noundef 4, 16 i /= 2; 17 // NATIVE: sdiv i32 18 // NATIVE: cmpxchg i32* {{.*}} seq_cst, align 4 19 // LIBCALL: sdiv i32 20 // LIBCALL: i1 @__atomic_compare_exchange(i32 noundef 4, 21 j /= x; 22 // NATIVE: sdiv i32 23 // NATIVE: cmpxchg i16* {{.*}} seq_cst, align 2 24 // LIBCALL: sdiv i32 25 // LIBCALL: i1 @__atomic_compare_exchange(i32 noundef 2, 26 27 } 28 29 // LIBCALL: declare void @__atomic_load(i32, i8*, i8*, i32) [[LC_ATTRS:#[0-9]+]] 30 // LIBCALL: declare i1 @__atomic_compare_exchange(i32, i8*, i8*, i8*, i32, i32) [[LC_ATTRS:#[0-9]+]] 31 32 extern _Atomic _Bool b; 33 34 _Bool bar() { 35 // NATIVE-LABEL: @bar 36 // NATIVE: %[[load:.*]] = load atomic i8, i8* @b seq_cst, align 1 37 // NATIVE: %[[tobool:.*]] = trunc i8 %[[load]] to i1 38 // NATIVE: ret i1 %[[tobool]] 39 // LIBCALL-LABEL: @bar 40 // LIBCALL: call void @__atomic_load(i32 noundef 1, i8* noundef @b, i8* noundef %atomic-temp, i32 noundef 5) 41 // LIBCALL: %[[load:.*]] = load i8, i8* %atomic-temp 42 // LIBCALL: %[[tobool:.*]] = trunc i8 %[[load]] to i1 43 // LIBCALL: ret i1 %[[tobool]] 44 45 return b; 46 } 47 48 extern _Atomic(_Complex int) x; 49 50 void baz(int y) { 51 // NATIVE-LABEL: @baz 52 // NATIVE: store atomic i64 {{.*}} seq_cst, align 8 53 // LIBCALL-LABEL: @baz 54 // LIBCALL: call void @__atomic_store 55 56 x += y; 57 } 58 59 // LIBCALL: declare void @__atomic_store(i32, i8*, i8*, i32) [[LC_ATTRS:#[0-9]+]] 60 61 _Atomic(int) compound_add(_Atomic(int) in) { 62 // CHECK-LABEL: @compound_add 63 // CHECK: [[OLD:%.*]] = atomicrmw add i32* {{.*}}, i32 5 seq_cst, align 4 64 // CHECK: [[NEW:%.*]] = add i32 [[OLD]], 5 65 // CHECK: ret i32 [[NEW]] 66 67 return (in += 5); 68 } 69 70 _Atomic(int) compound_sub(_Atomic(int) in) { 71 // CHECK-LABEL: @compound_sub 72 // CHECK: [[OLD:%.*]] = atomicrmw sub i32* {{.*}}, i32 5 seq_cst, align 4 73 // CHECK: [[NEW:%.*]] = sub i32 [[OLD]], 5 74 // CHECK: ret i32 [[NEW]] 75 76 return (in -= 5); 77 } 78 79 _Atomic(int) compound_xor(_Atomic(int) in) { 80 // CHECK-LABEL: @compound_xor 81 // CHECK: [[OLD:%.*]] = atomicrmw xor i32* {{.*}}, i32 5 seq_cst, align 4 82 // CHECK: [[NEW:%.*]] = xor i32 [[OLD]], 5 83 // CHECK: ret i32 [[NEW]] 84 85 return (in ^= 5); 86 } 87 88 _Atomic(int) compound_or(_Atomic(int) in) { 89 // CHECK-LABEL: @compound_or 90 // CHECK: [[OLD:%.*]] = atomicrmw or i32* {{.*}}, i32 5 seq_cst, align 4 91 // CHECK: [[NEW:%.*]] = or i32 [[OLD]], 5 92 // CHECK: ret i32 [[NEW]] 93 94 return (in |= 5); 95 } 96 97 _Atomic(int) compound_and(_Atomic(int) in) { 98 // CHECK-LABEL: @compound_and 99 // CHECK: [[OLD:%.*]] = atomicrmw and i32* {{.*}}, i32 5 seq_cst, align 4 100 // CHECK: [[NEW:%.*]] = and i32 [[OLD]], 5 101 // CHECK: ret i32 [[NEW]] 102 103 return (in &= 5); 104 } 105 106 _Atomic(int) compound_mul(_Atomic(int) in) { 107 // NATIVE-LABEL: @compound_mul 108 // NATIVE: cmpxchg i32* {{%.*}}, i32 {{%.*}}, i32 [[NEW:%.*]] seq_cst seq_cst, align 4 109 // NATIVE: ret i32 [[NEW]] 110 // LIBCALL-LABEL: @compound_mul 111 // LIBCALL: i1 @__atomic_compare_exchange(i32 noundef 4, 112 113 return (in *= 5); 114 } 115 116 // LIBCALL: [[LC_ATTRS]] = { nounwind willreturn } 117