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.
19 ; int *foo(struct ST *s) {
20 ; return &s[1].Z.B[5][13];
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 {
34 %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
39 ; atomic load with monotonic ordering
40 ; int load_monotonic(_Atomic int *num) {
41 ; int n = atomic_load_explicit(num, memory_order_relaxed);
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
56 ; atomic store with monotonic ordering.
57 ; void store_monotonic(_Atomic int *num) {
58 ; atomic_load_explicit(num, memory_order_relaxed);
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
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);
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
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);
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
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
115 ; TEST 7 - negative, should not deduce nosync
117 ; void volatile_store(volatile int *num) {
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
131 ; TEST 8 - negative, should not deduce nosync
133 ; int volatile_load(volatile int *num) {
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
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
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
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);
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);
205 ; TEST 12 - fences, negative
207 ; void foo1(int *a, std::atomic<bool> flag){
209 ; atomic_thread_fence(std::memory_order_release);
210 ; flag.store(true, std::memory_order_relaxed);
213 ; void bar(int *a, std::atomic<bool> flag){
214 ; while(!flag.load(std::memory_order_relaxed))
217 ; atomic_thread_fence(std::memory_order_acquire);
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
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
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
246 %5 = load atomic i8, i8* %3 monotonic, align 1
248 %7 = icmp eq i8 %6, 0
249 br i1 %7, label %4, label %8
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
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
279 %5 = load atomic i8, i8* %3 monotonic, align 1
281 %7 = icmp eq i8 %6, 0
282 br i1 %7, label %4, label %8
285 fence syncscope("singlethread") acquire
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)
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)
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)
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()
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*))
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)