xref: /llvm-project/llvm/test/Transforms/Attributor/nosync.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5
6; Test cases designed for the nosync function attribute.
7; FIXME's are used to indicate problems and missing attributes.
8
9; struct RT {
10;   char A;
11;   int B[10][20];
12;   char C;
13; };
14; struct ST {
15;   int X;
16;   double Y;
17;   struct RT Z;
18; };
19;
20; int *foo(struct ST *s) {
21;   return &s[1].Z.B[5][13];
22; }
23
24; TEST 1
25; non-convergent and readnone implies nosync
26%struct.RT = type { i8, [10 x [20 x i32]], i8 }
27%struct.ST = type { i32, double, %struct.RT }
28
29;.
30; CHECK: @a = common global i32 0, align 4
31;.
32define ptr @foo(ptr %s) nounwind optsize ssp memory(none) uwtable {
33; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind optsize ssp willreturn memory(none) uwtable
34; CHECK-LABEL: define {{[^@]+}}@foo
35; CHECK-SAME: (ptr nofree readnone "no-capture-maybe-returned" [[S:%.*]]) #[[ATTR0:[0-9]+]] {
36; CHECK-NEXT:  entry:
37; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], ptr [[S]], i64 1, i32 2, i32 1, i64 5, i64 13
38; CHECK-NEXT:    ret ptr [[ARRAYIDX]]
39;
40entry:
41  %arrayidx = getelementptr inbounds %struct.ST, ptr %s, i64 1, i32 2, i32 1, i64 5, i64 13
42  ret ptr %arrayidx
43}
44
45; TEST 2
46; atomic load with monotonic ordering
47; int load_monotonic(_Atomic int *num) {
48;   int n = atomic_load_explicit(num, memory_order_relaxed);
49;   return n;
50; }
51
52define i32 @load_monotonic(ptr nocapture readonly %arg) norecurse nounwind uwtable {
53; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
54; CHECK-LABEL: define {{[^@]+}}@load_monotonic
55; CHECK-SAME: (ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR1:[0-9]+]] {
56; CHECK-NEXT:    [[I:%.*]] = load atomic i32, ptr [[ARG]] monotonic, align 4
57; CHECK-NEXT:    ret i32 [[I]]
58;
59  %i = load atomic i32, ptr %arg monotonic, align 4
60  ret i32 %i
61}
62
63
64; TEST 3
65; atomic store with monotonic ordering.
66; void store_monotonic(_Atomic int *num) {
67;   atomic_load_explicit(num, memory_order_relaxed);
68; }
69
70define void @store_monotonic(ptr nocapture %arg) norecurse nounwind uwtable {
71; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
72; CHECK-LABEL: define {{[^@]+}}@store_monotonic
73; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR1]] {
74; CHECK-NEXT:    store atomic i32 10, ptr [[ARG]] monotonic, align 4
75; CHECK-NEXT:    ret void
76;
77  store atomic i32 10, ptr %arg monotonic, align 4
78  ret void
79}
80
81; TEST 4 - negative, should not deduce nosync
82; atomic load with acquire ordering.
83; int load_acquire(_Atomic int *num) {
84;   int n = atomic_load_explicit(num, memory_order_acquire);
85;   return n;
86; }
87
88define i32 @load_acquire(ptr nocapture readonly %arg) norecurse nounwind uwtable {
89; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
90; CHECK-LABEL: define {{[^@]+}}@load_acquire
91; CHECK-SAME: (ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]]) #[[ATTR2:[0-9]+]] {
92; CHECK-NEXT:    [[I:%.*]] = load atomic i32, ptr [[ARG]] acquire, align 4
93; CHECK-NEXT:    ret i32 [[I]]
94;
95  %i = load atomic i32, ptr %arg acquire, align 4
96  ret i32 %i
97}
98
99; TEST 5 - negative, should not deduce nosync
100; atomic load with release ordering
101; void load_release(_Atomic int *num) {
102;   atomic_store_explicit(num, 10, memory_order_release);
103; }
104
105define void @load_release(ptr nocapture %arg) norecurse nounwind uwtable {
106; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
107; CHECK-LABEL: define {{[^@]+}}@load_release
108; CHECK-SAME: (ptr nofree noundef writeonly align 4 captures(none) [[ARG:%.*]]) #[[ATTR2]] {
109; CHECK-NEXT:    store atomic volatile i32 10, ptr [[ARG]] release, align 4
110; CHECK-NEXT:    ret void
111;
112  store atomic volatile i32 10, ptr %arg release, align 4
113  ret void
114}
115
116; TEST 6 - negative volatile, relaxed atomic
117
118define void @load_volatile_release(ptr nocapture %arg) norecurse nounwind uwtable {
119; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
120; CHECK-LABEL: define {{[^@]+}}@load_volatile_release
121; CHECK-SAME: (ptr nofree noundef writeonly align 4 captures(none) [[ARG:%.*]]) #[[ATTR2]] {
122; CHECK-NEXT:    store atomic volatile i32 10, ptr [[ARG]] release, align 4
123; CHECK-NEXT:    ret void
124;
125  store atomic volatile i32 10, ptr %arg release, align 4
126  ret void
127}
128
129; TEST 7 - negative, should not deduce nosync
130; volatile store.
131; void volatile_store(volatile int *num) {
132;   *num = 14;
133; }
134
135define void @volatile_store(ptr %arg) norecurse nounwind uwtable {
136; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
137; CHECK-LABEL: define {{[^@]+}}@volatile_store
138; CHECK-SAME: (ptr nofree noundef align 4 [[ARG:%.*]]) #[[ATTR2]] {
139; CHECK-NEXT:    store volatile i32 14, ptr [[ARG]], align 4
140; CHECK-NEXT:    ret void
141;
142  store volatile i32 14, ptr %arg, align 4
143  ret void
144}
145
146; TEST 8 - negative, should not deduce nosync
147; volatile load.
148; int volatile_load(volatile int *num) {
149;   int n = *num;
150;   return n;
151; }
152
153define i32 @volatile_load(ptr %arg) norecurse nounwind uwtable {
154; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable
155; CHECK-LABEL: define {{[^@]+}}@volatile_load
156; CHECK-SAME: (ptr nofree noundef align 4 [[ARG:%.*]]) #[[ATTR2]] {
157; CHECK-NEXT:    [[I:%.*]] = load volatile i32, ptr [[ARG]], align 4
158; CHECK-NEXT:    ret i32 [[I]]
159;
160  %i = load volatile i32, ptr %arg, align 4
161  ret i32 %i
162}
163
164; TEST 9
165
166; CHECK: Function Attrs: noinline nosync nounwind uwtable
167declare void @nosync_function() noinline nounwind uwtable nosync
168
169define void @call_nosync_function() noinline nounwind uwtable {
170; CHECK: Function Attrs: noinline nosync nounwind uwtable
171; CHECK-LABEL: define {{[^@]+}}@call_nosync_function
172; CHECK-SAME: () #[[ATTR3:[0-9]+]] {
173; CHECK-NEXT:    tail call void @nosync_function() #[[ATTR4:[0-9]+]]
174; CHECK-NEXT:    ret void
175;
176  tail call void @nosync_function() noinline nounwind uwtable
177  ret void
178}
179
180; TEST 10 - negative, should not deduce nosync
181
182; CHECK: Function Attrs: noinline nounwind uwtable
183declare void @might_sync() noinline nounwind uwtable
184
185define void @call_might_sync() noinline nounwind uwtable {
186; CHECK: Function Attrs: noinline nounwind uwtable
187; CHECK-LABEL: define {{[^@]+}}@call_might_sync
188; CHECK-SAME: () #[[ATTR4]] {
189; CHECK-NEXT:    tail call void @might_sync() #[[ATTR4]]
190; CHECK-NEXT:    ret void
191;
192  tail call void @might_sync() noinline nounwind uwtable
193  ret void
194}
195
196; TEST 11 - positive, should deduce nosync
197; volatile operation in same scc but dead. Call volatile_load defined in TEST 8.
198
199define i32 @scc1(ptr %arg) noinline nounwind uwtable {
200; CHECK: Function Attrs: nofree noinline nounwind memory(argmem: readwrite) uwtable
201; CHECK-LABEL: define {{[^@]+}}@scc1
202; CHECK-SAME: (ptr nofree [[ARG:%.*]]) #[[ATTR5:[0-9]+]] {
203; CHECK-NEXT:    tail call void @scc2(ptr nofree [[ARG]]) #[[ATTR20:[0-9]+]]
204; CHECK-NEXT:    [[VAL:%.*]] = tail call i32 @volatile_load(ptr nofree noundef align 4 [[ARG]]) #[[ATTR20]]
205; CHECK-NEXT:    ret i32 [[VAL]]
206;
207  tail call void @scc2(ptr %arg)
208  %val = tail call i32 @volatile_load(ptr %arg)
209  ret i32 %val
210}
211
212define void @scc2(ptr %arg) noinline nounwind uwtable {
213; CHECK: Function Attrs: nofree noinline nounwind memory(argmem: readwrite) uwtable
214; CHECK-LABEL: define {{[^@]+}}@scc2
215; CHECK-SAME: (ptr nofree [[ARG:%.*]]) #[[ATTR5]] {
216; CHECK-NEXT:    [[I:%.*]] = tail call i32 @scc1(ptr nofree [[ARG]]) #[[ATTR20]]
217; CHECK-NEXT:    ret void
218;
219  %i = tail call i32 @scc1(ptr %arg)
220  ret void
221}
222
223; TEST 12 - fences, negative
224;
225; void foo1(int *a, std::atomic<bool> flag){
226;   *a = 100;
227;   atomic_thread_fence(std::memory_order_release);
228;   flag.store(true, std::memory_order_relaxed);
229; }
230;
231; void bar(int *a, std::atomic<bool> flag){
232;   while(!flag.load(std::memory_order_relaxed))
233;     ;
234;
235;   atomic_thread_fence(std::memory_order_acquire);
236;   int b = *a;
237; }
238
239%"struct.std::atomic" = type { %"struct.std::__atomic_base" }
240%"struct.std::__atomic_base" = type { i8 }
241
242define void @foo1(ptr %arg, ptr %arg1) {
243; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn
244; CHECK-LABEL: define {{[^@]+}}@foo1
245; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]], ptr nofree noundef nonnull writeonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR6:[0-9]+]] {
246; CHECK-NEXT:    store i32 100, ptr [[ARG]], align 4
247; CHECK-NEXT:    fence release
248; CHECK-NEXT:    store atomic i8 1, ptr [[ARG1]] monotonic, align 1
249; CHECK-NEXT:    ret void
250;
251  store i32 100, ptr %arg, align 4
252  fence release
253  store atomic i8 1, ptr %arg1 monotonic, align 1
254  ret void
255}
256
257define void @bar(ptr %arg, ptr %arg1) {
258; CHECK: Function Attrs: nofree norecurse nounwind
259; CHECK-LABEL: define {{[^@]+}}@bar
260; CHECK-SAME: (ptr nofree readnone captures(none) [[ARG:%.*]], ptr nofree nonnull readonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR7:[0-9]+]] {
261; CHECK-NEXT:    br label [[BB2:%.*]]
262; CHECK:       bb2:
263; CHECK-NEXT:    [[I3:%.*]] = load atomic i8, ptr [[ARG1]] monotonic, align 1
264; CHECK-NEXT:    [[I4:%.*]] = and i8 [[I3]], 1
265; CHECK-NEXT:    [[I5:%.*]] = icmp eq i8 [[I4]], 0
266; CHECK-NEXT:    br i1 [[I5]], label [[BB2]], label [[BB6:%.*]]
267; CHECK:       bb6:
268; CHECK-NEXT:    fence acquire
269; CHECK-NEXT:    ret void
270;
271  br label %bb2
272
273bb2:
274  %i3 = load atomic i8, ptr %arg1 monotonic, align 1
275  %i4 = and i8 %i3, 1
276  %i5 = icmp eq i8 %i4, 0
277  br i1 %i5, label %bb2, label %bb6
278
279bb6:
280  fence acquire
281  ret void
282}
283
284; TEST 13 - Fence syncscope("singlethread") seq_cst
285define void @foo1_singlethread(ptr %arg, ptr %arg1) {
286; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
287; CHECK-LABEL: define {{[^@]+}}@foo1_singlethread
288; CHECK-SAME: (ptr nofree noundef nonnull writeonly align 4 captures(none) dereferenceable(4) [[ARG:%.*]], ptr nofree noundef nonnull writeonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR8:[0-9]+]] {
289; CHECK-NEXT:    store i32 100, ptr [[ARG]], align 4
290; CHECK-NEXT:    fence syncscope("singlethread") release
291; CHECK-NEXT:    store atomic i8 1, ptr [[ARG1]] monotonic, align 1
292; CHECK-NEXT:    ret void
293;
294  store i32 100, ptr %arg, align 4
295  fence syncscope("singlethread") release
296  store atomic i8 1, ptr %arg1 monotonic, align 1
297  ret void
298}
299
300define void @bar_singlethread(ptr %arg, ptr %arg1) {
301; CHECK: Function Attrs: nofree norecurse nosync nounwind
302; CHECK-LABEL: define {{[^@]+}}@bar_singlethread
303; CHECK-SAME: (ptr nofree readnone captures(none) [[ARG:%.*]], ptr nofree nonnull readonly captures(none) dereferenceable(1) [[ARG1:%.*]]) #[[ATTR9:[0-9]+]] {
304; CHECK-NEXT:    br label [[BB2:%.*]]
305; CHECK:       bb2:
306; CHECK-NEXT:    [[I3:%.*]] = load atomic i8, ptr [[ARG1]] monotonic, align 1
307; CHECK-NEXT:    [[I4:%.*]] = and i8 [[I3]], 1
308; CHECK-NEXT:    [[I5:%.*]] = icmp eq i8 [[I4]], 0
309; CHECK-NEXT:    br i1 [[I5]], label [[BB2]], label [[BB6:%.*]]
310; CHECK:       bb6:
311; CHECK-NEXT:    fence syncscope("singlethread") acquire
312; CHECK-NEXT:    ret void
313;
314  br label %bb2
315
316bb2:
317  %i3 = load atomic i8, ptr %arg1 monotonic, align 1
318  %i4 = and i8 %i3, 1
319  %i5 = icmp eq i8 %i4, 0
320  br i1 %i5, label %bb2, label %bb6
321
322bb6:
323  fence syncscope("singlethread") acquire
324  ret void
325}
326
327declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
328declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)
329
330; TEST 14 - negative, checking volatile intrinsics.
331
332; It is odd to add nocapture but a result of the llvm.memcpy nocapture.
333;
334define i32 @memcpy_volatile(ptr %ptr1, ptr %ptr2) {
335; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite)
336; CHECK-LABEL: define {{[^@]+}}@memcpy_volatile
337; CHECK-SAME: (ptr nofree writeonly captures(none) [[PTR1:%.*]], ptr nofree readonly captures(none) [[PTR2:%.*]]) #[[ATTR12:[0-9]+]] {
338; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr nofree writeonly captures(none) [[PTR1]], ptr nofree readonly captures(none) [[PTR2]], i32 noundef 8, i1 noundef true) #[[ATTR21:[0-9]+]]
339; CHECK-NEXT:    ret i32 4
340;
341  call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 8, i1 true)
342  ret i32 4
343}
344
345; TEST 15 - positive, non-volatile intrinsic.
346
347; It is odd to add nocapture but a result of the llvm.memset nocapture.
348;
349define i32 @memset_non_volatile(ptr %ptr1, i8 %val) {
350; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
351; CHECK-LABEL: define {{[^@]+}}@memset_non_volatile
352; CHECK-SAME: (ptr nofree writeonly captures(none) [[PTR1:%.*]], i8 [[VAL:%.*]]) #[[ATTR13:[0-9]+]] {
353; CHECK-NEXT:    call void @llvm.memset.p0.i32(ptr nofree writeonly captures(none) [[PTR1]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR22:[0-9]+]]
354; CHECK-NEXT:    ret i32 4
355;
356  call void @llvm.memset.p0.i32(ptr %ptr1, i8 %val, i32 8, i1 false)
357  ret i32 4
358}
359
360; TEST 16 - negative, inline assembly.
361
362define i32 @inline_asm_test(i32 %x) {
363; CHECK-LABEL: define {{[^@]+}}@inline_asm_test
364; CHECK-SAME: (i32 [[X:%.*]]) {
365; CHECK-NEXT:    [[I:%.*]] = call i32 asm sideeffect "bswap $0", "=r,r"(i32 [[X]])
366; CHECK-NEXT:    ret i32 4
367;
368  %i = call i32 asm sideeffect "bswap $0", "=r,r"(i32 %x)
369  ret i32 4
370}
371
372declare void @readnone_test() convergent readnone
373
374; TEST 17 - negative. Convergent
375define void @convergent_readnone() {
376; CHECK: Function Attrs: memory(none)
377; CHECK-LABEL: define {{[^@]+}}@convergent_readnone
378; CHECK-SAME: () #[[ATTR15:[0-9]+]] {
379; CHECK-NEXT:    call void @readnone_test()
380; CHECK-NEXT:    ret void
381;
382  call void @readnone_test()
383  ret void
384}
385
386; CHECK: Function Attrs: nounwind
387declare void @llvm.x86.sse2.clflush(ptr)
388@a = common global i32 0, align 4
389
390; TEST 18 - negative. Synchronizing intrinsic
391
392define void @i_totally_sync() {
393; CHECK: Function Attrs: nounwind
394; CHECK-LABEL: define {{[^@]+}}@i_totally_sync
395; CHECK-SAME: () #[[ATTR16:[0-9]+]] {
396; CHECK-NEXT:    tail call void @llvm.x86.sse2.clflush(ptr noundef nonnull align 4 dereferenceable(4) @a)
397; CHECK-NEXT:    ret void
398;
399  tail call void @llvm.x86.sse2.clflush(ptr @a)
400  ret void
401}
402
403declare float @llvm.cos.f32(float %val) readnone
404
405; TEST 19 - positive, readnone & non-convergent intrinsic.
406
407define i32 @cos_test(float %x) {
408; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
409; CHECK-LABEL: define {{[^@]+}}@cos_test
410; CHECK-SAME: (float [[X:%.*]]) #[[ATTR18:[0-9]+]] {
411; CHECK-NEXT:    ret i32 4
412;
413  %i = call float @llvm.cos.f32(float %x)
414  ret i32 4
415}
416
417define float @cos_test2(float %x) {
418; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
419; CHECK-LABEL: define {{[^@]+}}@cos_test2
420; CHECK-SAME: (float [[X:%.*]]) #[[ATTR18]] {
421; CHECK-NEXT:    [[C:%.*]] = call nofpclass(inf) float @llvm.cos.f32(float [[X]]) #[[ATTR23:[0-9]+]]
422; CHECK-NEXT:    ret float [[C]]
423;
424  %c = call float @llvm.cos.f32(float %x)
425  ret float %c
426}
427
428declare void @unknown()
429define void @nosync_convergent_callee_test() {
430; CHECK: Function Attrs: nosync memory(none)
431; CHECK-LABEL: define {{[^@]+}}@nosync_convergent_callee_test
432; CHECK-SAME: () #[[ATTR19:[0-9]+]] {
433; CHECK-NEXT:    call void @unknown() #[[ATTR24:[0-9]+]]
434; CHECK-NEXT:    ret void
435;
436  call void @unknown() nosync convergent readnone
437  ret void
438}
439;.
440; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind optsize ssp willreturn memory(none) uwtable }
441; CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable }
442; CHECK: attributes #[[ATTR2]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) uwtable }
443; CHECK: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable }
444; CHECK: attributes #[[ATTR4]] = { noinline nounwind uwtable }
445; CHECK: attributes #[[ATTR5]] = { nofree noinline nounwind memory(argmem: readwrite) uwtable }
446; CHECK: attributes #[[ATTR6]] = { mustprogress nofree norecurse nounwind willreturn }
447; CHECK: attributes #[[ATTR7]] = { nofree norecurse nounwind }
448; CHECK: attributes #[[ATTR8]] = { mustprogress nofree norecurse nosync nounwind willreturn }
449; CHECK: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind }
450; CHECK: attributes #[[ATTR10:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
451; CHECK: attributes #[[ATTR11:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
452; CHECK: attributes #[[ATTR12]] = { mustprogress nofree norecurse nounwind willreturn memory(argmem: readwrite) }
453; CHECK: attributes #[[ATTR13]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
454; CHECK: attributes #[[ATTR14:[0-9]+]] = { convergent memory(none) }
455; CHECK: attributes #[[ATTR15]] = { memory(none) }
456; CHECK: attributes #[[ATTR16]] = { nounwind }
457; CHECK: attributes #[[ATTR17:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
458; CHECK: attributes #[[ATTR18]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
459; CHECK: attributes #[[ATTR19]] = { nosync memory(none) }
460; CHECK: attributes #[[ATTR20]] = { nofree nounwind }
461; CHECK: attributes #[[ATTR21]] = { nofree willreturn }
462; CHECK: attributes #[[ATTR22]] = { nofree willreturn memory(write) }
463; CHECK: attributes #[[ATTR23]] = { nofree nosync willreturn }
464; CHECK: attributes #[[ATTR24]] = { convergent nosync memory(none) }
465;.
466;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
467; CGSCC: {{.*}}
468; TUNIT: {{.*}}
469