xref: /llvm-project/llvm/test/Transforms/FunctionAttrs/nosync.ll (revision 4358e6e0c5b1f08de60b6b2fb015a06ab6760ee7)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes
2; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
3
4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5
6; Base case, empty function
7define void @test1() {
8; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
9; CHECK-LABEL: @test1(
10; CHECK-NEXT:    ret void
11;
12  ret void
13}
14
15; Show the bottom up walk
16define void @test2() {
17; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
18; CHECK-LABEL: @test2(
19; CHECK-NEXT:    call void @test1()
20; CHECK-NEXT:    ret void
21;
22  call void @test1()
23  ret void
24}
25
26declare void @unknown() convergent
27
28; Negative case with convergent function
29define void @test3() convergent {
30; CHECK: Function Attrs: convergent
31; CHECK-LABEL: @test3(
32; CHECK-NEXT:    call void @unknown()
33; CHECK-NEXT:    ret void
34;
35  call void @unknown()
36  ret void
37}
38
39define i32 @test4(i32 %a, i32 %b) {
40; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
41; CHECK-LABEL: @test4(
42; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
43; CHECK-NEXT:    ret i32 [[A]]
44;
45  %add = add i32 %a, %b
46  ret i32 %a
47}
48
49; negative case - explicit sync
50define void @test5(ptr %p) {
51; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
52; CHECK-LABEL: @test5(
53; CHECK-NEXT:    store atomic i8 0, ptr [[P:%.*]] seq_cst, align 1
54; CHECK-NEXT:    ret void
55;
56  store atomic i8 0, ptr %p seq_cst, align 1
57  ret void
58}
59
60; negative case - explicit sync
61define i8 @test6(ptr %p) {
62; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
63; CHECK-LABEL: @test6(
64; CHECK-NEXT:    [[V:%.*]] = load atomic i8, ptr [[P:%.*]] seq_cst, align 1
65; CHECK-NEXT:    ret i8 [[V]]
66;
67  %v = load atomic i8, ptr %p seq_cst, align 1
68  ret i8 %v
69}
70
71; negative case - explicit sync
72define void @test7(ptr %p) {
73; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
74; CHECK-LABEL: @test7(
75; CHECK-NEXT:    [[TMP1:%.*]] = atomicrmw add ptr [[P:%.*]], i8 0 seq_cst, align 1
76; CHECK-NEXT:    ret void
77;
78  atomicrmw add ptr %p, i8 0 seq_cst, align 1
79  ret void
80}
81
82; negative case - explicit sync
83define void @test8(ptr %p) {
84; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn
85; CHECK-LABEL: @test8(
86; CHECK-NEXT:    fence seq_cst
87; CHECK-NEXT:    ret void
88;
89  fence seq_cst
90  ret void
91}
92
93; singlethread fences are okay
94define void @test9(ptr %p) {
95; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
96; CHECK-LABEL: @test9(
97; CHECK-NEXT:    fence syncscope("singlethread") seq_cst
98; CHECK-NEXT:    ret void
99;
100  fence syncscope("singlethread") seq_cst
101  ret void
102}
103
104; atomic load with monotonic ordering
105define i32 @load_monotonic(ptr nocapture readonly %0) norecurse nounwind uwtable {
106; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
107; CHECK-LABEL: @load_monotonic(
108; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] monotonic, align 4
109; CHECK-NEXT:    ret i32 [[TMP2]]
110;
111  %2 = load atomic i32, ptr %0 monotonic, align 4
112  ret i32 %2
113}
114
115; atomic store with monotonic ordering.
116define void @store_monotonic(ptr nocapture %0) norecurse nounwind uwtable {
117; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
118; CHECK-LABEL: @store_monotonic(
119; CHECK-NEXT:    store atomic i32 10, ptr [[TMP0:%.*]] monotonic, align 4
120; CHECK-NEXT:    ret void
121;
122  store atomic i32 10, ptr %0 monotonic, align 4
123  ret void
124}
125
126; negative, should not deduce nosync
127; atomic load with acquire ordering.
128define i32 @load_acquire(ptr nocapture readonly %0) norecurse nounwind uwtable {
129; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
130; CHECK-LABEL: @load_acquire(
131; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] acquire, align 4
132; CHECK-NEXT:    ret i32 [[TMP2]]
133;
134  %2 = load atomic i32, ptr %0 acquire, align 4
135  ret i32 %2
136}
137
138define i32 @load_unordered(ptr nocapture readonly %0) norecurse nounwind uwtable {
139; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) uwtable
140; CHECK-LABEL: @load_unordered(
141; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, ptr [[TMP0:%.*]] unordered, align 4
142; CHECK-NEXT:    ret i32 [[TMP2]]
143;
144  %2 = load atomic i32, ptr %0 unordered, align 4
145  ret i32 %2
146}
147
148; atomic store with unordered ordering.
149define void @store_unordered(ptr nocapture %0) norecurse nounwind uwtable {
150; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) uwtable
151; CHECK-LABEL: @store_unordered(
152; CHECK-NEXT:    store atomic i32 10, ptr [[TMP0:%.*]] unordered, align 4
153; CHECK-NEXT:    ret void
154;
155  store atomic i32 10, ptr %0 unordered, align 4
156  ret void
157}
158
159
160; negative, should not deduce nosync
161; atomic load with release ordering
162define void @load_release(ptr nocapture %0) norecurse nounwind uwtable {
163; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
164; CHECK-LABEL: @load_release(
165; CHECK-NEXT:    store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4
166; CHECK-NEXT:    ret void
167;
168  store atomic volatile i32 10, ptr %0 release, align 4
169  ret void
170}
171
172; negative volatile, relaxed atomic
173define void @load_volatile_release(ptr nocapture %0) norecurse nounwind uwtable {
174; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
175; CHECK-LABEL: @load_volatile_release(
176; CHECK-NEXT:    store atomic volatile i32 10, ptr [[TMP0:%.*]] release, align 4
177; CHECK-NEXT:    ret void
178;
179  store atomic volatile i32 10, ptr %0 release, align 4
180  ret void
181}
182
183; volatile store.
184define void @volatile_store(ptr %0) norecurse nounwind uwtable {
185; CHECK: Function Attrs: nofree norecurse nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
186; CHECK-LABEL: @volatile_store(
187; CHECK-NEXT:    store volatile i32 14, ptr [[TMP0:%.*]], align 4
188; CHECK-NEXT:    ret void
189;
190  store volatile i32 14, ptr %0, align 4
191  ret void
192}
193
194; negative, should not deduce nosync
195; volatile load.
196define i32 @volatile_load(ptr %0) norecurse nounwind uwtable {
197; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) uwtable
198; CHECK-LABEL: @volatile_load(
199; CHECK-NEXT:    [[TMP2:%.*]] = load volatile i32, ptr [[TMP0:%.*]], align 4
200; CHECK-NEXT:    ret i32 [[TMP2]]
201;
202  %2 = load volatile i32, ptr %0, align 4
203  ret i32 %2
204}
205
206; CHECK: Function Attrs: noinline nosync nounwind uwtable
207; CHECK-NEXT: declare void @nosync_function()
208declare void @nosync_function() noinline nounwind uwtable nosync
209
210define void @call_nosync_function() nounwind uwtable noinline {
211; CHECK: Function Attrs: noinline nosync nounwind uwtable
212; CHECK-LABEL: @call_nosync_function(
213; CHECK-NEXT:    tail call void @nosync_function() #[[ATTR11:[0-9]+]]
214; CHECK-NEXT:    ret void
215;
216  tail call void @nosync_function() noinline nounwind uwtable
217  ret void
218}
219
220; CHECK: Function Attrs: noinline nounwind uwtable
221; CHECK-NEXT: declare void @might_sync()
222declare void @might_sync() noinline nounwind uwtable
223
224define void @call_might_sync() nounwind uwtable noinline {
225; CHECK: Function Attrs: noinline nounwind uwtable
226; CHECK-LABEL: @call_might_sync(
227; CHECK-NEXT:    tail call void @might_sync() #[[ATTR11]]
228; CHECK-NEXT:    ret void
229;
230  tail call void @might_sync() noinline nounwind uwtable
231  ret void
232}
233
234declare void @llvm.memcpy(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
235declare void @llvm.memset(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)
236
237; negative, checking volatile intrinsics.
238define i32 @memcpy_volatile(ptr %ptr1, ptr %ptr2) {
239; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
240; CHECK-LABEL: @memcpy_volatile(
241; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1:%.*]], ptr [[PTR2:%.*]], i32 8, i1 true)
242; CHECK-NEXT:    ret i32 4
243;
244  call void @llvm.memcpy(ptr %ptr1, ptr %ptr2, i32 8, i1 1)
245  ret i32 4
246}
247
248; positive, non-volatile intrinsic.
249define i32 @memset_non_volatile(ptr %ptr1, i8 %val) {
250; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
251; CHECK-LABEL: @memset_non_volatile(
252; CHECK-NEXT:    call void @llvm.memset.p0.i32(ptr [[PTR1:%.*]], i8 [[VAL:%.*]], i32 8, i1 false)
253; CHECK-NEXT:    ret i32 4
254;
255  call void @llvm.memset(ptr %ptr1, i8 %val, i32 8, i1 0)
256  ret i32 4
257}
258
259; negative, inline assembly.
260define i32 @inline_asm_test(i32 %x) {
261; CHECK-LABEL: @inline_asm_test(
262; CHECK-NEXT:    [[TMP1:%.*]] = call i32 asm "bswap $0", "=r,r"(i32 [[X:%.*]])
263; CHECK-NEXT:    ret i32 4
264;
265  call i32 asm "bswap $0", "=r,r"(i32 %x)
266  ret i32 4
267}
268
269declare void @readnone_test() convergent readnone
270
271; negative. Convergent
272define void @convergent_readnone(){
273; CHECK: Function Attrs: nofree nosync memory(none)
274; CHECK-LABEL: @convergent_readnone(
275; CHECK-NEXT:    call void @readnone_test()
276; CHECK-NEXT:    ret void
277;
278  call void @readnone_test()
279  ret void
280}
281
282; CHECK: Function Attrs: nounwind
283; CHECK-NEXT: declare void @llvm.x86.sse2.clflush(ptr)
284declare void @llvm.x86.sse2.clflush(ptr)
285@a = common global i32 0, align 4
286
287; negative. Synchronizing intrinsic
288define void @i_totally_sync() {
289; CHECK: Function Attrs: nounwind
290; CHECK-LABEL: @i_totally_sync(
291; CHECK-NEXT:    tail call void @llvm.x86.sse2.clflush(ptr @a)
292; CHECK-NEXT:    ret void
293;
294  tail call void @llvm.x86.sse2.clflush(ptr @a)
295  ret void
296}
297
298declare float @llvm.cos(float %val) readnone
299
300define float @cos_test(float %x) {
301; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
302; CHECK-LABEL: @cos_test(
303; CHECK-NEXT:    [[C:%.*]] = call float @llvm.cos.f32(float [[X:%.*]])
304; CHECK-NEXT:    ret float [[C]]
305;
306  %c = call float @llvm.cos(float %x)
307  ret float %c
308}
309