1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
3; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
4; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
5; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7
8; Test cases designed for the nosync function attribute.
9; FIXME's are used to indicate problems and missing attributes.
10
11; struct RT {
12;   char A;
13;   int B[10][20];
14;   char C;
15; };
16; struct ST {
17;   int X;
18;   double Y;
19;   struct RT Z;
20; };
21;
22; int *foo(struct ST *s) {
23;   return &s[1].Z.B[5][13];
24; }
25
26; TEST 1
27; non-convergent and readnone implies nosync
28%struct.RT = type { i8, [10 x [20 x i32]], i8 }
29%struct.ST = type { i32, double, %struct.RT }
30
31;.
32; CHECK: @[[A:[a-zA-Z0-9_$"\\.-]+]] = common global i32 0, align 4
33;.
34define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
35; IS__TUNIT____: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable willreturn
36; IS__TUNIT____-LABEL: define {{[^@]+}}@foo
37; IS__TUNIT____-SAME: (%struct.ST* nofree readnone "no-capture-maybe-returned" [[S:%.*]]) #[[ATTR0:[0-9]+]] {
38; IS__TUNIT____-NEXT:  entry:
39; IS__TUNIT____-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S]], i64 1, i32 2, i32 1, i64 5, i64 13
40; IS__TUNIT____-NEXT:    ret i32* [[ARRAYIDX]]
41;
42; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn
43; IS__CGSCC____-LABEL: define {{[^@]+}}@foo
44; IS__CGSCC____-SAME: (%struct.ST* nofree readnone "no-capture-maybe-returned" [[S:%.*]]) #[[ATTR0:[0-9]+]] {
45; IS__CGSCC____-NEXT:  entry:
46; IS__CGSCC____-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S]], i64 1, i32 2, i32 1, i64 5, i64 13
47; IS__CGSCC____-NEXT:    ret i32* [[ARRAYIDX]]
48;
49entry:
50  %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
51  ret i32* %arrayidx
52}
53
54; TEST 2
55; atomic load with monotonic ordering
56; int load_monotonic(_Atomic int *num) {
57;   int n = atomic_load_explicit(num, memory_order_relaxed);
58;   return n;
59; }
60
61define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable {
62; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable willreturn
63; CHECK-LABEL: define {{[^@]+}}@load_monotonic
64; CHECK-SAME: (i32* nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]]) #[[ATTR1:[0-9]+]] {
65; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, i32* [[TMP0]] monotonic, align 4
66; CHECK-NEXT:    ret i32 [[TMP2]]
67;
68  %2 = load atomic i32, i32* %0 monotonic, align 4
69  ret i32 %2
70}
71
72
73; TEST 3
74; atomic store with monotonic ordering.
75; void store_monotonic(_Atomic int *num) {
76;   atomic_load_explicit(num, memory_order_relaxed);
77; }
78
79define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
80; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind uwtable willreturn
81; CHECK-LABEL: define {{[^@]+}}@store_monotonic
82; CHECK-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]]) #[[ATTR1]] {
83; CHECK-NEXT:    store atomic i32 10, i32* [[TMP0]] monotonic, align 4
84; CHECK-NEXT:    ret void
85;
86  store atomic i32 10, i32* %0 monotonic, align 4
87  ret void
88}
89
90; TEST 4 - negative, should not deduce nosync
91; atomic load with acquire ordering.
92; int load_acquire(_Atomic int *num) {
93;   int n = atomic_load_explicit(num, memory_order_acquire);
94;   return n;
95; }
96
97define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable {
98; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn
99; CHECK-LABEL: define {{[^@]+}}@load_acquire
100; CHECK-SAME: (i32* nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[TMP0:%.*]]) #[[ATTR2:[0-9]+]] {
101; CHECK-NEXT:    [[TMP2:%.*]] = load atomic i32, i32* [[TMP0]] acquire, align 4
102; CHECK-NEXT:    ret i32 [[TMP2]]
103;
104  %2 = load atomic i32, i32* %0 acquire, align 4
105  ret i32 %2
106}
107
108; TEST 5 - negative, should not deduce nosync
109; atomic load with release ordering
110; void load_release(_Atomic int *num) {
111;   atomic_store_explicit(num, 10, memory_order_release);
112; }
113
114define void @load_release(i32* nocapture %0) norecurse nounwind uwtable {
115; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn
116; CHECK-LABEL: define {{[^@]+}}@load_release
117; CHECK-SAME: (i32* nocapture nofree noundef writeonly align 4 [[TMP0:%.*]]) #[[ATTR2]] {
118; CHECK-NEXT:    store atomic volatile i32 10, i32* [[TMP0]] release, align 4
119; CHECK-NEXT:    ret void
120;
121  store atomic volatile i32 10, i32* %0 release, align 4
122  ret void
123}
124
125; TEST 6 - negative volatile, relaxed atomic
126
127define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable {
128; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn
129; CHECK-LABEL: define {{[^@]+}}@load_volatile_release
130; CHECK-SAME: (i32* nocapture nofree noundef writeonly align 4 [[TMP0:%.*]]) #[[ATTR2]] {
131; CHECK-NEXT:    store atomic volatile i32 10, i32* [[TMP0]] release, align 4
132; CHECK-NEXT:    ret void
133;
134  store atomic volatile i32 10, i32* %0 release, align 4
135  ret void
136}
137
138; TEST 7 - negative, should not deduce nosync
139; volatile store.
140; void volatile_store(volatile int *num) {
141;   *num = 14;
142; }
143
144define void @volatile_store(i32* %0) norecurse nounwind uwtable {
145; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn
146; CHECK-LABEL: define {{[^@]+}}@volatile_store
147; CHECK-SAME: (i32* nofree noundef align 4 [[TMP0:%.*]]) #[[ATTR2]] {
148; CHECK-NEXT:    store volatile i32 14, i32* [[TMP0]], align 4
149; CHECK-NEXT:    ret void
150;
151  store volatile i32 14, i32* %0, align 4
152  ret void
153}
154
155; TEST 8 - negative, should not deduce nosync
156; volatile load.
157; int volatile_load(volatile int *num) {
158;   int n = *num;
159;   return n;
160; }
161
162define i32 @volatile_load(i32* %0) norecurse nounwind uwtable {
163; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable willreturn
164; CHECK-LABEL: define {{[^@]+}}@volatile_load
165; CHECK-SAME: (i32* nofree align 4 [[TMP0:%.*]]) #[[ATTR2]] {
166; CHECK-NEXT:    [[TMP2:%.*]] = load volatile i32, i32* [[TMP0]], align 4
167; CHECK-NEXT:    ret i32 [[TMP2]]
168;
169  %2 = load volatile i32, i32* %0, align 4
170  ret i32 %2
171}
172
173; TEST 9
174
175; CHECK: Function Attrs: noinline nosync nounwind uwtable
176; CHECK-NEXT: declare void @nosync_function()
177declare void @nosync_function() noinline nounwind uwtable nosync
178
179define void @call_nosync_function() nounwind uwtable noinline {
180; CHECK: Function Attrs: noinline nosync nounwind uwtable
181; CHECK-LABEL: define {{[^@]+}}@call_nosync_function
182; CHECK-SAME: () #[[ATTR3:[0-9]+]] {
183; CHECK-NEXT:    tail call void @nosync_function() #[[ATTR4:[0-9]+]]
184; CHECK-NEXT:    ret void
185;
186  tail call void @nosync_function() noinline nounwind uwtable
187  ret void
188}
189
190; TEST 10 - negative, should not deduce nosync
191
192; CHECK: Function Attrs: noinline nounwind uwtable
193; CHECK-NEXT: declare void @might_sync()
194declare void @might_sync() noinline nounwind uwtable
195
196define void @call_might_sync() nounwind uwtable noinline {
197; CHECK: Function Attrs: noinline nounwind uwtable
198; CHECK-LABEL: define {{[^@]+}}@call_might_sync
199; CHECK-SAME: () #[[ATTR4]] {
200; CHECK-NEXT:    tail call void @might_sync() #[[ATTR4]]
201; CHECK-NEXT:    ret void
202;
203  tail call void @might_sync() noinline nounwind uwtable
204  ret void
205}
206
207; TEST 11 - positive, should deduce nosync
208; volatile operation in same scc but dead. Call volatile_load defined in TEST 8.
209
210define i32 @scc1(i32* %0) noinline nounwind uwtable {
211; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn
212; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@scc1
213; NOT_CGSCC_NPM-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]]) #[[ATTR5:[0-9]+]] {
214; NOT_CGSCC_NPM-NEXT:    unreachable
215;
216; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
217; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@scc1
218; IS__CGSCC_NPM-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]]) #[[ATTR5:[0-9]+]] {
219; IS__CGSCC_NPM-NEXT:    unreachable
220;
221  tail call void @scc2(i32* %0);
222  %val = tail call i32 @volatile_load(i32* %0);
223  ret i32 %val;
224}
225
226define void @scc2(i32* %0) noinline nounwind uwtable {
227; NOT_CGSCC_NPM: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable willreturn
228; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@scc2
229; NOT_CGSCC_NPM-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]]) #[[ATTR5]] {
230; NOT_CGSCC_NPM-NEXT:    unreachable
231;
232; IS__CGSCC_NPM: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn
233; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@scc2
234; IS__CGSCC_NPM-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]]) #[[ATTR5]] {
235; IS__CGSCC_NPM-NEXT:    unreachable
236;
237  tail call i32 @scc1(i32* %0);
238  ret void;
239}
240
241; TEST 12 - fences, negative
242;
243; void foo1(int *a, std::atomic<bool> flag){
244;   *a = 100;
245;   atomic_thread_fence(std::memory_order_release);
246;   flag.store(true, std::memory_order_relaxed);
247; }
248;
249; void bar(int *a, std::atomic<bool> flag){
250;   while(!flag.load(std::memory_order_relaxed))
251;     ;
252;
253;   atomic_thread_fence(std::memory_order_acquire);
254;   int b = *a;
255; }
256
257%"struct.std::atomic" = type { %"struct.std::__atomic_base" }
258%"struct.std::__atomic_base" = type { i8 }
259
260define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
261; IS__TUNIT____: Function Attrs: nofree nounwind willreturn
262; IS__TUNIT____-LABEL: define {{[^@]+}}@foo1
263; IS__TUNIT____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR6:[0-9]+]] {
264; IS__TUNIT____-NEXT:    store i32 100, i32* [[TMP0]], align 4
265; IS__TUNIT____-NEXT:    fence release
266; IS__TUNIT____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
267; IS__TUNIT____-NEXT:    store atomic i8 1, i8* [[TMP3]] monotonic, align 1
268; IS__TUNIT____-NEXT:    ret void
269;
270; IS__CGSCC____: Function Attrs: nofree norecurse nounwind willreturn
271; IS__CGSCC____-LABEL: define {{[^@]+}}@foo1
272; IS__CGSCC____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR6:[0-9]+]] {
273; IS__CGSCC____-NEXT:    store i32 100, i32* [[TMP0]], align 4
274; IS__CGSCC____-NEXT:    fence release
275; IS__CGSCC____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
276; IS__CGSCC____-NEXT:    store atomic i8 1, i8* [[TMP3]] monotonic, align 1
277; IS__CGSCC____-NEXT:    ret void
278;
279  store i32 100, i32* %0, align 4
280  fence release
281  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
282  store atomic i8 1, i8* %3 monotonic, align 1
283  ret void
284}
285
286define void @bar(i32* %0, %"struct.std::atomic"* %1) {
287; IS__TUNIT____: Function Attrs: nofree nounwind
288; IS__TUNIT____-LABEL: define {{[^@]+}}@bar
289; IS__TUNIT____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR7:[0-9]+]] {
290; IS__TUNIT____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
291; IS__TUNIT____-NEXT:    br label [[TMP4:%.*]]
292; IS__TUNIT____:       4:
293; IS__TUNIT____-NEXT:    [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1
294; IS__TUNIT____-NEXT:    [[TMP6:%.*]] = and i8 [[TMP5]], 1
295; IS__TUNIT____-NEXT:    [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0
296; IS__TUNIT____-NEXT:    br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]]
297; IS__TUNIT____:       8:
298; IS__TUNIT____-NEXT:    fence acquire
299; IS__TUNIT____-NEXT:    ret void
300;
301; IS__CGSCC____: Function Attrs: nofree norecurse nounwind
302; IS__CGSCC____-LABEL: define {{[^@]+}}@bar
303; IS__CGSCC____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR7:[0-9]+]] {
304; IS__CGSCC____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
305; IS__CGSCC____-NEXT:    br label [[TMP4:%.*]]
306; IS__CGSCC____:       4:
307; IS__CGSCC____-NEXT:    [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1
308; IS__CGSCC____-NEXT:    [[TMP6:%.*]] = and i8 [[TMP5]], 1
309; IS__CGSCC____-NEXT:    [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0
310; IS__CGSCC____-NEXT:    br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]]
311; IS__CGSCC____:       8:
312; IS__CGSCC____-NEXT:    fence acquire
313; IS__CGSCC____-NEXT:    ret void
314;
315  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
316  br label %4
317
3184:                                                ; preds = %4, %2
319  %5 = load atomic i8, i8* %3  monotonic, align 1
320  %6 = and i8 %5, 1
321  %7 = icmp eq i8 %6, 0
322  br i1 %7, label %4, label %8
323
3248:                                                ; preds = %4
325  fence acquire
326  ret void
327}
328
329; TEST 13 - Fence syncscope("singlethread") seq_cst
330define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
331; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn
332; IS__TUNIT____-LABEL: define {{[^@]+}}@foo1_singlethread
333; IS__TUNIT____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR8:[0-9]+]] {
334; IS__TUNIT____-NEXT:    store i32 100, i32* [[TMP0]], align 4
335; IS__TUNIT____-NEXT:    fence syncscope("singlethread") release
336; IS__TUNIT____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
337; IS__TUNIT____-NEXT:    store atomic i8 1, i8* [[TMP3]] monotonic, align 1
338; IS__TUNIT____-NEXT:    ret void
339;
340; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn
341; IS__CGSCC____-LABEL: define {{[^@]+}}@foo1_singlethread
342; IS__CGSCC____-SAME: (i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull writeonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR8:[0-9]+]] {
343; IS__CGSCC____-NEXT:    store i32 100, i32* [[TMP0]], align 4
344; IS__CGSCC____-NEXT:    fence syncscope("singlethread") release
345; IS__CGSCC____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
346; IS__CGSCC____-NEXT:    store atomic i8 1, i8* [[TMP3]] monotonic, align 1
347; IS__CGSCC____-NEXT:    ret void
348;
349  store i32 100, i32* %0, align 4
350  fence syncscope("singlethread") release
351  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
352  store atomic i8 1, i8* %3 monotonic, align 1
353  ret void
354}
355
356define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) {
357; IS__TUNIT____: Function Attrs: nofree nosync nounwind
358; IS__TUNIT____-LABEL: define {{[^@]+}}@bar_singlethread
359; IS__TUNIT____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR9:[0-9]+]] {
360; IS__TUNIT____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
361; IS__TUNIT____-NEXT:    br label [[TMP4:%.*]]
362; IS__TUNIT____:       4:
363; IS__TUNIT____-NEXT:    [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1
364; IS__TUNIT____-NEXT:    [[TMP6:%.*]] = and i8 [[TMP5]], 1
365; IS__TUNIT____-NEXT:    [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0
366; IS__TUNIT____-NEXT:    br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]]
367; IS__TUNIT____:       8:
368; IS__TUNIT____-NEXT:    fence syncscope("singlethread") acquire
369; IS__TUNIT____-NEXT:    ret void
370;
371; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind
372; IS__CGSCC____-LABEL: define {{[^@]+}}@bar_singlethread
373; IS__CGSCC____-SAME: (i32* nocapture nofree readnone [[TMP0:%.*]], %"struct.std::atomic"* nocapture nofree nonnull readonly dereferenceable(1) [[TMP1:%.*]]) #[[ATTR9:[0-9]+]] {
374; IS__CGSCC____-NEXT:    [[TMP3:%.*]] = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* [[TMP1]], i64 0, i32 0, i32 0
375; IS__CGSCC____-NEXT:    br label [[TMP4:%.*]]
376; IS__CGSCC____:       4:
377; IS__CGSCC____-NEXT:    [[TMP5:%.*]] = load atomic i8, i8* [[TMP3]] monotonic, align 1
378; IS__CGSCC____-NEXT:    [[TMP6:%.*]] = and i8 [[TMP5]], 1
379; IS__CGSCC____-NEXT:    [[TMP7:%.*]] = icmp eq i8 [[TMP6]], 0
380; IS__CGSCC____-NEXT:    br i1 [[TMP7]], label [[TMP4]], label [[TMP8:%.*]]
381; IS__CGSCC____:       8:
382; IS__CGSCC____-NEXT:    fence syncscope("singlethread") acquire
383; IS__CGSCC____-NEXT:    ret void
384;
385  %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
386  br label %4
387
3884:                                                ; preds = %4, %2
389  %5 = load atomic i8, i8* %3  monotonic, align 1
390  %6 = and i8 %5, 1
391  %7 = icmp eq i8 %6, 0
392  br i1 %7, label %4, label %8
393
3948:                                                ; preds = %4
395  fence syncscope("singlethread") acquire
396  ret void
397}
398
399declare void @llvm.memcpy(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
400declare void @llvm.memset(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
401
402; TEST 14 - negative, checking volatile intrinsics.
403
404; It is odd to add nocapture but a result of the llvm.memcpy nocapture.
405;
406define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
407; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn
408; IS__TUNIT____-LABEL: define {{[^@]+}}@memcpy_volatile
409; IS__TUNIT____-SAME: (i8* nocapture nofree writeonly [[PTR1:%.*]], i8* nocapture nofree readonly [[PTR2:%.*]]) #[[ATTR10:[0-9]+]] {
410; IS__TUNIT____-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[PTR1]], i8* noalias nocapture nofree readonly [[PTR2]], i32 noundef 8, i1 noundef true) #[[ATTR17:[0-9]+]]
411; IS__TUNIT____-NEXT:    ret i32 4
412;
413; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind willreturn
414; IS__CGSCC____-LABEL: define {{[^@]+}}@memcpy_volatile
415; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[PTR1:%.*]], i8* nocapture nofree readonly [[PTR2:%.*]]) #[[ATTR10:[0-9]+]] {
416; IS__CGSCC____-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[PTR1]], i8* noalias nocapture nofree readonly [[PTR2]], i32 noundef 8, i1 noundef true) #[[ATTR18:[0-9]+]]
417; IS__CGSCC____-NEXT:    ret i32 4
418;
419  call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1)
420  ret i32 4
421}
422
423; TEST 15 - positive, non-volatile intrinsic.
424
425; It is odd to add nocapture but a result of the llvm.memset nocapture.
426;
427define i32 @memset_non_volatile(i8* %ptr1, i8 %val) {
428; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
429; IS__TUNIT____-LABEL: define {{[^@]+}}@memset_non_volatile
430; IS__TUNIT____-SAME: (i8* nocapture nofree writeonly [[PTR1:%.*]], i8 [[VAL:%.*]]) #[[ATTR11:[0-9]+]] {
431; IS__TUNIT____-NEXT:    call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[PTR1]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR18:[0-9]+]]
432; IS__TUNIT____-NEXT:    ret i32 4
433;
434; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly
435; IS__CGSCC____-LABEL: define {{[^@]+}}@memset_non_volatile
436; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[PTR1:%.*]], i8 [[VAL:%.*]]) #[[ATTR11:[0-9]+]] {
437; IS__CGSCC____-NEXT:    call void @llvm.memset.p0i8.i32(i8* nocapture nofree writeonly [[PTR1]], i8 [[VAL]], i32 noundef 8, i1 noundef false) #[[ATTR19:[0-9]+]]
438; IS__CGSCC____-NEXT:    ret i32 4
439;
440  call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0)
441  ret i32 4
442}
443
444; TEST 16 - negative, inline assembly.
445
446define i32 @inline_asm_test(i32 %x) {
447; CHECK-LABEL: define {{[^@]+}}@inline_asm_test
448; CHECK-SAME: (i32 [[X:%.*]]) {
449; CHECK-NEXT:    [[TMP1:%.*]] = call i32 asm "bswap $0", "=r,r"(i32 [[X]])
450; CHECK-NEXT:    ret i32 4
451;
452  call i32 asm "bswap $0", "=r,r"(i32 %x)
453  ret i32 4
454}
455
456declare void @readnone_test() convergent readnone
457
458; TEST 17 - negative. Convergent
459define void @convergent_readnone(){
460; CHECK: Function Attrs: readnone
461; CHECK-LABEL: define {{[^@]+}}@convergent_readnone
462; CHECK-SAME: () #[[ATTR13:[0-9]+]] {
463; CHECK-NEXT:    call void @readnone_test()
464; CHECK-NEXT:    ret void
465;
466  call void @readnone_test()
467  ret void
468}
469
470; CHECK: Function Attrs: nounwind
471; CHECK-NEXT: declare void @llvm.x86.sse2.clflush(i8*)
472declare void @llvm.x86.sse2.clflush(i8*)
473@a = common global i32 0, align 4
474
475; TEST 18 - negative. Synchronizing intrinsic
476
477define void @i_totally_sync() {
478; CHECK: Function Attrs: nounwind
479; CHECK-LABEL: define {{[^@]+}}@i_totally_sync
480; CHECK-SAME: () #[[ATTR14:[0-9]+]] {
481; CHECK-NEXT:    tail call void @llvm.x86.sse2.clflush(i8* noundef nonnull align 4 dereferenceable(4) bitcast (i32* @a to i8*))
482; CHECK-NEXT:    ret void
483;
484  tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*))
485  ret void
486}
487
488declare float @llvm.cos(float %val) readnone
489
490; TEST 19 - positive, readnone & non-convergent intrinsic.
491
492define i32 @cos_test(float %x) {
493; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
494; IS__TUNIT____-LABEL: define {{[^@]+}}@cos_test
495; IS__TUNIT____-SAME: (float [[X:%.*]]) #[[ATTR15:[0-9]+]] {
496; IS__TUNIT____-NEXT:    ret i32 4
497;
498; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
499; IS__CGSCC____-LABEL: define {{[^@]+}}@cos_test
500; IS__CGSCC____-SAME: (float [[X:%.*]]) #[[ATTR15:[0-9]+]] {
501; IS__CGSCC____-NEXT:    ret i32 4
502;
503  call float @llvm.cos(float %x)
504  ret i32 4
505}
506
507define float @cos_test2(float %x) {
508; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
509; IS__TUNIT____-LABEL: define {{[^@]+}}@cos_test2
510; IS__TUNIT____-SAME: (float [[X:%.*]]) #[[ATTR15]] {
511; IS__TUNIT____-NEXT:    [[C:%.*]] = call float @llvm.cos.f32(float [[X]]) #[[ATTR19:[0-9]+]]
512; IS__TUNIT____-NEXT:    ret float [[C]]
513;
514; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone willreturn
515; IS__CGSCC____-LABEL: define {{[^@]+}}@cos_test2
516; IS__CGSCC____-SAME: (float [[X:%.*]]) #[[ATTR16:[0-9]+]] {
517; IS__CGSCC____-NEXT:    [[C:%.*]] = call float @llvm.cos.f32(float [[X]]) #[[ATTR20:[0-9]+]]
518; IS__CGSCC____-NEXT:    ret float [[C]]
519;
520  %c = call float @llvm.cos(float %x)
521  ret float %c
522}
523;.
524; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind optsize readnone ssp uwtable willreturn }
525; IS__TUNIT____: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind uwtable willreturn }
526; IS__TUNIT____: attributes #[[ATTR2]] = { argmemonly nofree norecurse nounwind uwtable willreturn }
527; IS__TUNIT____: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable }
528; IS__TUNIT____: attributes #[[ATTR4]] = { noinline nounwind uwtable }
529; IS__TUNIT____: attributes #[[ATTR5]] = { nofree noinline noreturn nosync nounwind readnone uwtable willreturn }
530; IS__TUNIT____: attributes #[[ATTR6]] = { nofree nounwind willreturn }
531; IS__TUNIT____: attributes #[[ATTR7]] = { nofree nounwind }
532; IS__TUNIT____: attributes #[[ATTR8]] = { nofree nosync nounwind willreturn }
533; IS__TUNIT____: attributes #[[ATTR9]] = { nofree nosync nounwind }
534; IS__TUNIT____: attributes #[[ATTR10]] = { argmemonly nofree nosync nounwind willreturn }
535; IS__TUNIT____: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly }
536; IS__TUNIT____: attributes #[[ATTR12:[0-9]+]] = { convergent readnone }
537; IS__TUNIT____: attributes #[[ATTR13]] = { readnone }
538; IS__TUNIT____: attributes #[[ATTR14]] = { nounwind }
539; IS__TUNIT____: attributes #[[ATTR15]] = { nofree nosync nounwind readnone willreturn }
540; IS__TUNIT____: attributes #[[ATTR16:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn }
541; IS__TUNIT____: attributes #[[ATTR17]] = { willreturn }
542; IS__TUNIT____: attributes #[[ATTR18]] = { willreturn writeonly }
543; IS__TUNIT____: attributes #[[ATTR19]] = { readnone willreturn }
544;.
545; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn }
546; IS__CGSCC_OPM: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind uwtable willreturn }
547; IS__CGSCC_OPM: attributes #[[ATTR2]] = { argmemonly nofree norecurse nounwind uwtable willreturn }
548; IS__CGSCC_OPM: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable }
549; IS__CGSCC_OPM: attributes #[[ATTR4]] = { noinline nounwind uwtable }
550; IS__CGSCC_OPM: attributes #[[ATTR5]] = { nofree noinline noreturn nosync nounwind readnone uwtable willreturn }
551; IS__CGSCC_OPM: attributes #[[ATTR6]] = { nofree norecurse nounwind willreturn }
552; IS__CGSCC_OPM: attributes #[[ATTR7]] = { nofree norecurse nounwind }
553; IS__CGSCC_OPM: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind willreturn }
554; IS__CGSCC_OPM: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind }
555; IS__CGSCC_OPM: attributes #[[ATTR10]] = { argmemonly nofree nosync nounwind willreturn }
556; IS__CGSCC_OPM: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly }
557; IS__CGSCC_OPM: attributes #[[ATTR12:[0-9]+]] = { convergent readnone }
558; IS__CGSCC_OPM: attributes #[[ATTR13]] = { readnone }
559; IS__CGSCC_OPM: attributes #[[ATTR14]] = { nounwind }
560; IS__CGSCC_OPM: attributes #[[ATTR15]] = { nofree norecurse nosync nounwind readnone willreturn }
561; IS__CGSCC_OPM: attributes #[[ATTR16]] = { nofree nosync nounwind readnone willreturn }
562; IS__CGSCC_OPM: attributes #[[ATTR17:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn }
563; IS__CGSCC_OPM: attributes #[[ATTR18]] = { willreturn }
564; IS__CGSCC_OPM: attributes #[[ATTR19]] = { willreturn writeonly }
565; IS__CGSCC_OPM: attributes #[[ATTR20]] = { readnone willreturn }
566;.
567; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind optsize readnone ssp uwtable willreturn }
568; IS__CGSCC_NPM: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind uwtable willreturn }
569; IS__CGSCC_NPM: attributes #[[ATTR2]] = { argmemonly nofree norecurse nounwind uwtable willreturn }
570; IS__CGSCC_NPM: attributes #[[ATTR3]] = { noinline nosync nounwind uwtable }
571; IS__CGSCC_NPM: attributes #[[ATTR4]] = { noinline nounwind uwtable }
572; IS__CGSCC_NPM: attributes #[[ATTR5]] = { nofree noinline norecurse noreturn nosync nounwind readnone uwtable willreturn }
573; IS__CGSCC_NPM: attributes #[[ATTR6]] = { nofree norecurse nounwind willreturn }
574; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nofree norecurse nounwind }
575; IS__CGSCC_NPM: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind willreturn }
576; IS__CGSCC_NPM: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind }
577; IS__CGSCC_NPM: attributes #[[ATTR10]] = { argmemonly nofree nosync nounwind willreturn }
578; IS__CGSCC_NPM: attributes #[[ATTR11]] = { argmemonly nofree nosync nounwind willreturn writeonly }
579; IS__CGSCC_NPM: attributes #[[ATTR12:[0-9]+]] = { convergent readnone }
580; IS__CGSCC_NPM: attributes #[[ATTR13]] = { readnone }
581; IS__CGSCC_NPM: attributes #[[ATTR14]] = { nounwind }
582; IS__CGSCC_NPM: attributes #[[ATTR15]] = { nofree norecurse nosync nounwind readnone willreturn }
583; IS__CGSCC_NPM: attributes #[[ATTR16]] = { nofree nosync nounwind readnone willreturn }
584; IS__CGSCC_NPM: attributes #[[ATTR17:[0-9]+]] = { nofree nosync nounwind readnone speculatable willreturn }
585; IS__CGSCC_NPM: attributes #[[ATTR18]] = { willreturn }
586; IS__CGSCC_NPM: attributes #[[ATTR19]] = { willreturn writeonly }
587; IS__CGSCC_NPM: attributes #[[ATTR20]] = { readnone willreturn }
588;.
589