[InstCombine] Signed saturation patterns
[llvm-complete.git] / test / Transforms / FunctionAttrs / nosync.ll
blob381c5abb26148b0980867256f98c208bdf695dc7
1 ; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
2 ; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
3 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5 ; Test cases designed for the nosync function attribute.
6 ; FIXME's are used to indicate problems and missing attributes.
8 ; struct RT {
9 ;   char A;
10 ;   int B[10][20];
11 ;   char C;
12 ; };
13 ; struct ST {
14 ;   int X;
15 ;   double Y;
16 ;   struct RT Z;
17 ; };
19 ; int *foo(struct ST *s) {
20 ;   return &s[1].Z.B[5][13];
21 ; }
23 ; TEST 1
24 ; non-convergent and readnone implies nosync
25 %struct.RT = type { i8, [10 x [20 x i32]], i8 }
26 %struct.ST = type { i32, double, %struct.RT }
28 ; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable
29 ; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s)
30 ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable
31 ; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* readnone "no-capture-maybe-returned" %s)
32 define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
33 entry:
34   %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
35   ret i32* %arrayidx
38 ; TEST 2
39 ; atomic load with monotonic ordering
40 ; int load_monotonic(_Atomic int *num) {
41 ;   int n = atomic_load_explicit(num, memory_order_relaxed);
42 ;   return n;
43 ; }
45 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
46 ; FNATTR-NEXT: define i32 @load_monotonic(i32* nocapture readonly %0)
47 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
48 ; ATTRIBUTOR-NEXT: define i32 @load_monotonic(i32* nocapture nonnull readonly dereferenceable(4) %0)
49 define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable {
50   %2 = load atomic i32, i32* %0 monotonic, align 4
51   ret i32 %2
55 ; TEST 3
56 ; atomic store with monotonic ordering.
57 ; void store_monotonic(_Atomic int *num) {
58 ;   atomic_load_explicit(num, memory_order_relaxed);
59 ; }
61 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
62 ; FNATTR-NEXT: define void @store_monotonic(i32* nocapture %0)
63 ; ATTRIBUTOR: Function Attrs: nofree norecurse nosync nounwind uwtable
64 ; ATTRIBUTOR-NEXT: define void @store_monotonic(i32* nocapture nonnull writeonly dereferenceable(4) %0) 
65 define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
66   store atomic i32 10, i32* %0 monotonic, align 4
67   ret void
70 ; TEST 4 - negative, should not deduce nosync
71 ; atomic load with acquire ordering.
72 ; int load_acquire(_Atomic int *num) {
73 ;   int n = atomic_load_explicit(num, memory_order_acquire);
74 ;   return n;
75 ; }
77 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
78 ; FNATTR-NEXT: define i32 @load_acquire(i32* nocapture readonly %0)
79 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
80 ; ATTRIBUTOR-NOT: nosync
81 ; ATTRIBUTOR-NEXT: define i32 @load_acquire(i32* nocapture nonnull readonly dereferenceable(4) %0)
82 define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable {
83   %2 = load atomic i32, i32* %0 acquire, align 4
84   ret i32 %2
87 ; TEST 5 - negative, should not deduce nosync
88 ; atomic load with release ordering
89 ; void load_release(_Atomic int *num) {
90 ;   atomic_store_explicit(num, 10, memory_order_release);
91 ; }
93 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
94 ; FNATTR-NEXT: define void @load_release(i32* nocapture %0)
95 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
96 ; ATTRIBUTOR-NOT: nosync
97 ; ATTRIBUTOR-NEXT: define void @load_release(i32* nocapture writeonly %0)
98 define void @load_release(i32* nocapture %0) norecurse nounwind uwtable {
99   store atomic volatile i32 10, i32* %0 release, align 4
100   ret void
103 ; TEST 6 - negative volatile, relaxed atomic
105 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
106 ; FNATTR-NEXT: define void @load_volatile_release(i32* nocapture %0)
107 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
108 ; ATTRIBUTOR-NOT: nosync
109 ; ATTRIBUTOR-NEXT: define void @load_volatile_release(i32* nocapture writeonly %0)
110 define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable {
111   store atomic volatile i32 10, i32* %0 release, align 4
112   ret void
115 ; TEST 7 - negative, should not deduce nosync
116 ; volatile store.
117 ; void volatile_store(volatile int *num) {
118 ;   *num = 14;
119 ; }
121 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
122 ; FNATTR-NEXT: define void @volatile_store(i32* %0)
123 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
124 ; ATTRIBUTOR-NOT: nosync
125 ; ATTRIBUTOR-NEXT: define void @volatile_store(i32* %0)
126 define void @volatile_store(i32* %0) norecurse nounwind uwtable {
127   store volatile i32 14, i32* %0, align 4
128   ret void
131 ; TEST 8 - negative, should not deduce nosync
132 ; volatile load.
133 ; int volatile_load(volatile int *num) {
134 ;   int n = *num;
135 ;   return n;
136 ; }
138 ; FNATTR: Function Attrs: nofree norecurse nounwind uwtable
139 ; FNATTR-NEXT: define i32 @volatile_load(i32* %0)
140 ; ATTRIBUTOR: Function Attrs: nofree norecurse nounwind uwtable
141 ; ATTRIBUTOR-NOT: nosync
142 ; ATTRIBUTOR-NEXT: define i32 @volatile_load(i32* %0)
143 define i32 @volatile_load(i32* %0) norecurse nounwind uwtable {
144   %2 = load volatile i32, i32* %0, align 4
145   ret i32 %2
148 ; TEST 9
150 ; FNATTR: Function Attrs: noinline nosync nounwind uwtable
151 ; FNATTR-NEXT: declare void @nosync_function()
152 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
153 ; ATTRIBUTOR-NEXT: declare void @nosync_function()
154 declare void @nosync_function() noinline nounwind uwtable nosync
156 ; FNATTR: Function Attrs: noinline nounwind uwtable
157 ; FNATTR-NEXT: define void @call_nosync_function()
158 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
159 ; ATTRIBUTOR-next: define void @call_nosync_function()
160 define void @call_nosync_function() nounwind uwtable noinline {
161   tail call void @nosync_function() noinline nounwind uwtable
162   ret void
165 ; TEST 10 - negative, should not deduce nosync
167 ; FNATTR: Function Attrs: noinline nounwind uwtable
168 ; FNATTR-NEXT: declare void @might_sync()
169 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
170 ; ATTRIBUTOR-NEXT: declare void @might_sync()
171 declare void @might_sync() noinline nounwind uwtable
173 ; FNATTR: Function Attrs: noinline nounwind uwtable
174 ; FNATTR-NEXT: define void @call_might_sync()
175 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
176 ; ATTRIBUTOR-NOT: nosync
177 ; ATTRIBUTOR-NEXT: define void @call_might_sync()
178 define void @call_might_sync() nounwind uwtable noinline {
179   tail call void @might_sync() noinline nounwind uwtable
180   ret void
183 ; TEST 11 - positive, should deduce nosync
184 ; volatile operation in same scc but dead. Call volatile_load defined in TEST 8.
186 ; FNATTR: Function Attrs: nofree noinline nounwind uwtable
187 ; FNATTR-NEXT: define i32 @scc1(i32* %0)
188 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
189 ; ATTRIBUTOR-NEXT: define i32 @scc1(i32* nocapture readnone %0)
190 define i32 @scc1(i32* %0) noinline nounwind uwtable {
191   tail call void @scc2(i32* %0);
192   %val = tail call i32 @volatile_load(i32* %0);
193   ret i32 %val;
196 ; FNATTR: Function Attrs: nofree noinline nounwind uwtable
197 ; FNATTR-NEXT: define void @scc2(i32* %0)
198 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable
199 ; ATTRIBUTOR-NEXT: define void @scc2(i32* nocapture readnone %0)
200 define void @scc2(i32* %0) noinline nounwind uwtable {
201   tail call i32 @scc1(i32* %0);
202   ret void;
205 ; TEST 12 - fences, negative
207 ; void foo1(int *a, std::atomic<bool> flag){
208 ;   *a = 100;
209 ;   atomic_thread_fence(std::memory_order_release);
210 ;   flag.store(true, std::memory_order_relaxed);
211 ; }
213 ; void bar(int *a, std::atomic<bool> flag){
214 ;   while(!flag.load(std::memory_order_relaxed))
215 ;     ;
217 ;   atomic_thread_fence(std::memory_order_acquire);
218 ;   int b = *a;
219 ; }
221 %"struct.std::atomic" = type { %"struct.std::__atomic_base" }
222 %"struct.std::__atomic_base" = type { i8 }
224 ; FNATTR: Function Attrs: nofree norecurse nounwind
225 ; FNATTR-NEXT: define void @foo1(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
226 ; ATTRIBUTOR-NOT: nosync
227 ; ATTRIBUTOR: define void @foo1(i32* nocapture nonnull writeonly dereferenceable(4) %0, %"struct.std::atomic"* nocapture writeonly %1)
229 define void @foo1(i32* %0, %"struct.std::atomic"* %1) {
230   store i32 100, i32* %0, align 4
231   fence release
232   %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
233   store atomic i8 1, i8* %3 monotonic, align 1
234   ret void
237 ; FNATTR: Function Attrs: nofree norecurse nounwind
238 ; FNATTR-NEXT: define void @bar(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
239 ; ATTRIBUTOR-NOT: nosync
240 ; ATTRIBUTOR: define void @bar(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
241 define void @bar(i32* %0, %"struct.std::atomic"* %1) {
242   %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
243   br label %4
245 4:                                                ; preds = %4, %2
246   %5 = load atomic i8, i8* %3  monotonic, align 1
247   %6 = and i8 %5, 1
248   %7 = icmp eq i8 %6, 0
249   br i1 %7, label %4, label %8
251 8:                                                ; preds = %4
252   fence acquire
253   ret void
256 ; TEST 13 - Fence syncscope("singlethread") seq_cst
257 ; FNATTR: Function Attrs: nofree norecurse nounwind
258 ; FNATTR-NEXT: define void @foo1_singlethread(i32* nocapture %0, %"struct.std::atomic"* nocapture %1)
259 ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind willreturn
260 ; ATTRIBUTOR: define void @foo1_singlethread(i32* nocapture nonnull writeonly dereferenceable(4) %0, %"struct.std::atomic"* nocapture writeonly %1)
262 define void @foo1_singlethread(i32* %0, %"struct.std::atomic"* %1) {
263   store i32 100, i32* %0, align 4
264   fence syncscope("singlethread") release
265   %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
266   store atomic i8 1, i8* %3 monotonic, align 1
267   ret void
270 ; FNATTR: Function Attrs: nofree norecurse nounwind
271 ; FNATTR-NEXT: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
272 ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind
273 ; ATTRIBUTOR: define void @bar_singlethread(i32* nocapture readnone %0, %"struct.std::atomic"* nocapture readonly %1)
274 define void @bar_singlethread(i32* %0, %"struct.std::atomic"* %1) {
275   %3 = getelementptr inbounds %"struct.std::atomic", %"struct.std::atomic"* %1, i64 0, i32 0, i32 0
276   br label %4
278 4:                                                ; preds = %4, %2
279   %5 = load atomic i8, i8* %3  monotonic, align 1
280   %6 = and i8 %5, 1
281   %7 = icmp eq i8 %6, 0
282   br i1 %7, label %4, label %8
284 8:                                                ; preds = %4
285   fence syncscope("singlethread") acquire
286   ret void
289 declare void @llvm.memcpy(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
290 declare void @llvm.memset(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
292 ; TEST 14 - negative, checking volatile intrinsics.
294 ; It is odd to add nocapture but a result of the llvm.memcpy nocapture.
296 ; ATTRIBUTOR: Function Attrs: nounwind
297 ; ATTRIBUTOR-NOT: nosync
298 ; ATTRIBUTOR-NEXT: define i32 @memcpy_volatile(i8* nocapture writeonly %ptr1, i8* nocapture readonly %ptr2)
299 define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
300   call void @llvm.memcpy(i8* %ptr1, i8* %ptr2, i32 8, i1 1)
301   ret i32 4
304 ; TEST 15 - positive, non-volatile intrinsic.
306 ; It is odd to add nocapture but a result of the llvm.memset nocapture.
308 ; ATTRIBUTOR: Function Attrs: nosync
309 ; ATTRIBUTOR-NEXT: define i32 @memset_non_volatile(i8* nocapture writeonly %ptr1, i8 %val)
310 define i32 @memset_non_volatile(i8* %ptr1, i8 %val) {
311   call void @llvm.memset(i8* %ptr1, i8 %val, i32 8, i1 0)
312   ret i32 4
315 ; TEST 16 - negative, inline assembly.
317 ; ATTRIBUTOR: define i32 @inline_asm_test(i32 %x)
318 define i32 @inline_asm_test(i32 %x) {
319   call i32 asm "bswap $0", "=r,r"(i32 %x)
320   ret i32 4
323 declare void @readnone_test() convergent readnone
325 ; ATTRIBUTOR: define void @convergent_readnone()
326 ; TEST 17 - negative. Convergent
327 define void @convergent_readnone(){
328     call void @readnone_test()
329     ret void
332 ; ATTRIBUTOR: Function Attrs: nounwind
333 ; ATTRIBUTOR-NEXT: declare void @llvm.x86.sse2.clflush(i8*)
334 declare void @llvm.x86.sse2.clflush(i8*)
335 @a = common global i32 0, align 4
337 ; TEST 18 - negative. Synchronizing intrinsic
339 ; ATTRIBUTOR: Function Attrs: nounwind
340 ; ATTRIBUTOR-NOT: nosync
341 ; ATTRIBUTOR-NEXT: define void @i_totally_sync()
342 define void @i_totally_sync() {
343   tail call void @llvm.x86.sse2.clflush(i8* bitcast (i32* @a to i8*))
344   ret void
347 declare float @llvm.cos(float %val) readnone
349 ; TEST 19 - positive, readnone & non-convergent intrinsic.
351 ; ATTRIBUTOR: Function Attrs: nosync nounwind
352 ; ATTRIBUTOR-NEXT: define i32 @cos_test(float %x)
353 define i32 @cos_test(float %x) {
354   call float @llvm.cos(float %x)
355   ret i32 4