1 ; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
2 ; RUN: opt -attributor --attributor-disable=false -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
5 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7 ; Test cases specifically designed for the "willreturn" function attribute.
8 ; We use FIXME's to indicate problems and missing attributes.
11 ; TEST 1 (positive case)
12 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
13 ; FNATTR-NEXT: define void @only_return()
14 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable willreturn
15 ; ATTRIBUTOR-NEXT: define void @only_return()
16 define void @only_return() #0 {
21 ; TEST 2 (positive & negative case)
23 ; recursive function which will halt
25 ; return n<=1? n : fib(n-1) + fib(n-2);
28 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
29 ; FNATTR-NEXT: define i32 @fib(i32 %0)
30 ; FIXME: missing willreturn
31 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
32 ; ATTRIBUTOR-NEXT: define i32 @fib(i32 %0) local_unnamed_addr
33 define i32 @fib(i32 %0) local_unnamed_addr #0 {
34 %2 = icmp slt i32 %0, 2
35 br i1 %2, label %9, label %3
37 ; <label>:3: ; preds = %1
38 %4 = add nsw i32 %0, -1
39 %5 = tail call i32 @fib(i32 %4)
40 %6 = add nsw i32 %0, -2
41 %7 = tail call i32 @fib(i32 %6)
42 %8 = add nsw i32 %7, %5
45 ; <label>:9: ; preds = %1
50 ; recursive function which doesn't stop for some input.
51 ; int fact_maybe_not_halt(int n) {
55 ; return fact_maybe_not_halt( n > 0 ? n-1 : n) * n;
57 ; fact_maybe_not(-1) doesn't stop.
59 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
60 ; FNATTR-NOT: willreturn
61 ; FNATTR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
62 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
63 ; ATTRIBUTOR-NOT: willreturn
64 ; ATTRIBUTOR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
65 define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 {
66 %2 = icmp eq i32 %0, 0
67 br i1 %2, label %11, label %3
69 ; <label>:3: ; preds = %1, %3
70 %4 = phi i32 [ %8, %3 ], [ %0, %1 ]
71 %5 = phi i32 [ %9, %3 ], [ 1, %1 ]
72 %6 = icmp sgt i32 %4, 0
73 %7 = sext i1 %6 to i32
74 %8 = add nsw i32 %4, %7
75 %9 = mul nsw i32 %4, %5
76 %10 = icmp eq i32 %8, 0
77 br i1 %10, label %11, label %3
79 ; <label>:11: ; preds = %3, %1
80 %12 = phi i32 [ 1, %1 ], [ %9, %3 ]
85 ; TEST 3 (positive case)
87 ; int fact_loop(int n ){
89 ; for(int i = 1;i<=n;i++){
95 ; FIXME: missing willreturn
96 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
97 ; FNATTR-NEXT: define i32 @fact_loop(i32 %0)
98 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
99 ; ATTRIBUTOR-NEXT: define i32 @fact_loop(i32 %0) local_unnamed_addr
100 define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
101 %2 = icmp slt i32 %0, 1
102 br i1 %2, label %3, label %5
104 ; <label>:3: ; preds = %5, %1
105 %4 = phi i32 [ 1, %1 ], [ %8, %5 ]
108 ; <label>:5: ; preds = %1, %5
109 %6 = phi i32 [ %9, %5 ], [ 1, %1 ]
110 %7 = phi i32 [ %8, %5 ], [ 1, %1 ]
111 %8 = mul nsw i32 %6, %7
112 %9 = add nuw nsw i32 %6, 1
113 %10 = icmp eq i32 %6, %0
114 br i1 %10, label %3, label %5
117 ; TEST 4 (negative case)
119 ; void mutual_recursion1(){
120 ; mutual_recursion2();
122 ; void mutual_recursion2(){
123 ; mutual_recursion1();
126 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
127 ; FNATTR-NOT: willreturn
128 ; FNATTR-NEXT: define void @mutual_recursion1(i1 %c)
129 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
130 ; ATTRIBUTOR-NOT: willreturn
131 ; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c)
132 define void @mutual_recursion1(i1 %c) #0 {
133 br i1 %c, label %rec, label %end
135 call void @mutual_recursion2(i1 %c)
142 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
143 ; FNATTR-NOT: willreturn
144 ; FNATTR-NEXT: define void @mutual_recursion2(i1 %c)
145 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
146 ; ATTRIBUTOR-NOT: willreturn
147 ; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c)
148 define void @mutual_recursion2(i1 %c) #0 {
149 call void @mutual_recursion1(i1 %c)
154 ; TEST 5 (negative case)
155 ; call exit/abort (has noreturn attribute)
156 ; FNATTR: Function Attrs: noreturn
157 ; FNATTR-NEXT: declare void @exit(i32) local_unnamed_addr
158 ; ATTRIBUTOR: Function Attrs: noreturn
159 ; ATTRIBUTOR-NEXT: declare void @exit(i32) local_unnamed_add
160 declare void @exit(i32 %0) local_unnamed_addr noreturn
162 ; FNATTR: Function Attrs: noinline nounwind uwtable
163 ; FNATTR-NOT: willreturn
164 ; FNATTR-NEXT: define void @only_exit()
165 ; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
166 ; ATTRIBUTOR-NOT: willreturn
167 ; ATTRIBUTOR-NEXT: define void @only_exit() local_unnamed_addr
168 define void @only_exit() local_unnamed_addr #0 {
169 tail call void @exit(i32 0)
174 ; void conditional_exit(int cond, int *p){
183 ; FNATTR: Function Attrs: noinline nounwind uwtable
184 ; FNATTR-NOT: willreturn
185 ; FNATTR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
186 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
187 ; ATTRIBUTOR-NOT: willreturn
188 ; ATTRIBUTOR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
189 define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 {
190 %3 = icmp eq i32 %0, 0
191 br i1 %3, label %5, label %4
193 ; <label>:4: ; preds = %2
194 tail call void @exit(i32 0)
197 ; <label>:5: ; preds = %2
198 %6 = load i32, i32* %1, align 4
199 %7 = icmp eq i32 %6, 0
200 br i1 %7, label %9, label %8
202 ; <label>:8: ; preds = %5
203 tail call void @exit(i32 1)
206 ; <label>:9: ; preds = %5
210 ; TEST 6 (positive case)
211 ; Call intrinsic function
212 ; FIXME: missing willreturn
213 ; FNATTRS: Function Attrs: noinline readnone speculatable
214 ; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0)
215 ; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
216 ; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
217 declare float @llvm.floor.f32(float)
219 ; FNATTRS: Function Attrs: noinline nounwind uwtable
220 ; FNATTRS-NEXT: define void @call_floor(float %a)
221 ; FIXME: missing willreturn
222 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind uwtable
223 ; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
224 define void @call_floor(float %a) #0 {
225 tail call float @llvm.floor.f32(float %a)
230 ; TEST 7 (negative case)
231 ; Call function declaration without willreturn
233 ; FNATTR: Function Attrs: noinline nounwind uwtable
234 ; FNATTR-NOT: willreturn
235 ; FNATTR-NEXT: declare void @maybe_noreturn()
236 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
237 ; ATTRIBUTOR-NOT: willreturn
238 ; ATTRIBUTOR-NEXT: declare void @maybe_noreturn()
239 declare void @maybe_noreturn() #0
241 ; FNATTR: Function Attrs: noinline nounwind uwtable
242 ; FNATTR-NOT: willreturn
243 ; FNATTR-NEXT: define void @call_maybe_noreturn()
244 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
245 ; ATTRIBUTOR-NOT: willreturn
246 ; ATTRIBUTOR-NEXT: define void @call_maybe_noreturn()
247 define void @call_maybe_noreturn() #0 {
248 tail call void @maybe_noreturn()
253 ; TEST 8 (positive case)
256 ; FNATTR: Function Attrs: willreturn
257 ; FNATTR-NEXT: declare void @will_return()
258 ; ATTRIBUTOR: Function Attrs: willreturn
259 ; ATTRIBUTOR-NEXT: declare void @will_return()
260 declare void @will_return() willreturn
262 ; FIXME: missing willreturn
263 ; FNATTR: Function Attrs: noinline nounwind uwtable
264 ; FNATTR-NEXT: define void @f1()
265 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
266 ; ATTRIBUTOR-NEXT: define void @f1()
267 define void @f1() #0 {
268 tail call void @will_return()
272 ; FIXME: missing willreturn
273 ; FNATTR: Function Attrs: noinline nounwind uwtable
274 ; FNATTR-NEXT: define void @f2()
275 ; FIXME: missing willreturn
276 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
277 ; ATTRIBUTOR-NEXT: define void @f2()
278 define void @f2() #0 {
284 ; TEST 9 (negative case)
285 ; call willreturn function in endless loop.
287 ; FNATTR: Function Attrs: noinline nounwind uwtable
288 ; FNATTR-NOT: willreturn
289 ; FNATTR-NEXT: define void @call_will_return_but_has_loop()
290 ; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
291 ; ATTRIBUTOR-NOT: willreturn
292 ; ATTRIBUTOR-NEXT: define void @call_will_return_but_has_loop()
293 define void @call_will_return_but_has_loop() #0 {
296 tail call void @will_return()
303 ; TEST 10 (positive case)
304 ; invoke a function with willreturn
306 ; FNATTR: Function Attrs: noinline uwtable willreturn
307 ; FNATTR-NEXT: declare i1 @maybe_raise_exception()
308 ; ATTRIBUTOR: Function Attrs: noinline uwtable willreturn
309 ; ATTRIBUTOR-NEXT: declare i1 @maybe_raise_exception()
310 declare i1 @maybe_raise_exception() #1 willreturn
312 ; FNATTR: Function Attrs: nounwind
313 ; FNATTR-NEXT: define void @invoke_test()
314 ; ATTRIBUTOR: Function Attrs: nounwind willreturn
315 ; ATTRIBUTOR-NEXT: define void @invoke_test()
316 define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 {
317 invoke i1 @maybe_raise_exception()
318 to label %N unwind label %F
322 %val = landingpad { i8*, i32 }
327 declare i32 @__gxx_personality_v0(...)
330 ; TEST 11 (positive case)
331 ; counstant trip count
332 ; int loop_constant_trip_count(int*p){
334 ; for(int i = 0;i<10;i++){
340 ; FIXME: missing willreturn
341 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
342 ; FNATTR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0)
343 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
344 ; ATTRIBUTOR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0)
345 define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 {
348 ; <label>:2: ; preds = %3
351 ; <label>:3: ; preds = %3, %1
352 %4 = phi i64 [ 0, %1 ], [ %9, %3 ]
353 %5 = phi i32 [ 0, %1 ], [ %8, %3 ]
354 %6 = getelementptr inbounds i32, i32* %0, i64 %4
355 %7 = load i32, i32* %6, align 4
356 %8 = add nsw i32 %7, %5
357 %9 = add nuw nsw i64 %4, 1
358 %10 = icmp eq i64 %9, 10
359 br i1 %10, label %2, label %3
363 ; TEST 12 (negative case)
364 ; unbounded trip count
366 ; int loop_trip_count_unbound(unsigned s,unsigned e, int *p, int offset){
368 ; for(unsigned i = s;i != e;i+=offset){
373 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
374 ; FNATTR-NOT: willreturn
375 ; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
376 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
377 ; ATTRIBUTOR-NOT: willreturn
378 ; ATTRIBUTOR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
379 define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr #0 {
380 %5 = icmp eq i32 %0, %1
381 br i1 %5, label %6, label %8
383 ; <label>:6: ; preds = %8, %4
384 %7 = phi i32 [ 0, %4 ], [ %14, %8 ]
387 ; <label>:8: ; preds = %4, %8
388 %9 = phi i32 [ %15, %8 ], [ %0, %4 ]
389 %10 = phi i32 [ %14, %8 ], [ 0, %4 ]
390 %11 = zext i32 %9 to i64
391 %12 = getelementptr inbounds i32, i32* %2, i64 %11
392 %13 = load i32, i32* %12, align 4
393 %14 = add nsw i32 %13, %10
395 %16 = icmp eq i32 %15, %1
396 br i1 %16, label %6, label %8
400 ; TEST 13 (positive case)
401 ; Function Attrs: norecurse nounwind readonly uwtable
402 ; int loop_trip_dec(int n, int *p){
411 ; FIXME: missing willreturn
412 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
413 ; FNATTR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1)
414 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
415 ; ATTRIBUTOR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
417 define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 {
418 %3 = icmp sgt i32 %0, -1
419 br i1 %3, label %4, label %14
421 ; <label>:4: ; preds = %2
422 %5 = sext i32 %0 to i64
425 ; <label>:6: ; preds = %4, %6
426 %7 = phi i64 [ %5, %4 ], [ %12, %6 ]
427 %8 = phi i32 [ 0, %4 ], [ %11, %6 ]
428 %9 = getelementptr inbounds i32, i32* %1, i64 %7
429 %10 = load i32, i32* %9, align 4
430 %11 = add nsw i32 %10, %8
431 %12 = add nsw i64 %7, -1
432 %13 = icmp sgt i64 %7, 0
433 br i1 %13, label %6, label %14
435 ; <label>:14: ; preds = %6, %2
436 %15 = phi i32 [ 0, %2 ], [ %11, %6 ]
440 ; TEST 14 (positive case)
443 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
444 ; FNATTR-NEXT: define i32 @multiple_return(i32 %a)
445 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable willreturn
446 ; ATTRIBUTOR-NEXT: define i32 @multiple_return(i32 %a)
447 define i32 @multiple_return(i32 %a) #0 {
448 %b = icmp eq i32 %a, 0
449 br i1 %b, label %t, label %f
457 ; TEST 15 (positive & negative case)
460 ; 15.1 (positive case)
461 ; FNATTR: Function Attrs: noinline nounwind uwtable
462 ; FNATTR-NEXT: define void @unreachable_exit_positive1()
463 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable willreturn
464 ; ATTRIBUTOR-NEXT: define void @unreachable_exit_positive1()
465 define void @unreachable_exit_positive1() #0 {
466 tail call void @will_return()
470 tail call void @exit(i32 0)
474 ; FIXME: missing willreturn
475 ; FNATTR: Function Attrs: noinline nounwind uwtable
476 ; FNATTR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
477 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
478 ; ATTRIBUTOR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
479 define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 {
480 %2 = icmp slt i32 %0, 1
481 br i1 %2, label %3, label %5
483 ; <label>:3: ; preds = %5, %1
484 %4 = phi i32 [ 1, %1 ], [ %8, %5 ]
487 ; <label>:5: ; preds = %1, %5
488 %6 = phi i32 [ %9, %5 ], [ 1, %1 ]
489 %7 = phi i32 [ %8, %5 ], [ 1, %1 ]
490 %8 = mul nsw i32 %6, %7
491 %9 = add nuw nsw i32 %6, 1
492 %10 = icmp eq i32 %6, %0
493 br i1 %10, label %3, label %5
496 tail call void @exit(i32 0)
503 ; FNATTR: Function Attrs: noinline nounwind uwtable
504 ; FNATTR-NOT: willreturn
505 ; FNATTR-NEXT: define void @unreachable_exit_negative1()
506 ; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
507 ; ATTRIBUTOR-NOT: willreturn
508 ; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative1()
509 define void @unreachable_exit_negative1() #0 {
510 tail call void @exit(i32 0)
514 tail call void @exit(i32 0)
518 ; FNATTR: Function Attrs: noinline nounwind uwtable
519 ; FNATTR-NOT: willreturn
520 ; FNATTR-NEXT: define void @unreachable_exit_negative2()
521 ; ATTRIBUTOR: Function Attrs: nofree noinline noreturn nosync nounwind uwtable
522 ; ATTRIBUTOR-NOT: willreturn
523 ; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative2()
524 define void @unreachable_exit_negative2() #0 {
533 tail call void @exit(i32 0)
537 ; FNATTR: Function Attrs: noreturn nounwind
538 ; FNATTR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
539 ; ATTRIBUTOR: Function Attrs: noreturn nounwind
540 ; ATTRIBUTOR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
541 declare void @llvm.eh.sjlj.longjmp(i8*)
543 ; FNATTR: Function Attrs: noinline nounwind uwtable
544 ; FNATTR-NOT: willreturn
545 ; FNATTR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #3 {
546 ; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
547 ; ATTRIBUTOR-NOT: willreturn
548 ; ATTRIBUTOR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr
549 define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #0 {
550 tail call void @llvm.eh.sjlj.longjmp(i8* %0)
555 attributes #0 = { nounwind uwtable noinline }
556 attributes #1 = { uwtable noinline }