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