| ; RUN: opt -function-attrs -S %s | FileCheck %s |
| |
| define void @mustprogress_readnone() mustprogress { |
| ; CHECK: Function Attrs: {{.*}} noreturn {{.*}} readnone willreturn |
| ; CHECK-NEXT: define void @mustprogress_readnone() |
| ; |
| entry: |
| br label %while.body |
| |
| while.body: |
| br label %while.body |
| } |
| |
| define i32 @mustprogress_load(i32* %ptr) mustprogress { |
| ; CHECK: Function Attrs: {{.*}} readonly willreturn |
| ; CHECK-NEXT: define i32 @mustprogress_load( |
| ; |
| entry: |
| br label %while.body |
| |
| while.body: |
| %r = load i32, i32* %ptr |
| br label %while.body |
| } |
| |
| define void @mustprogress_store(i32* %ptr) mustprogress { |
| ; CHECK-NOT: Function Attrs: {{.*}} willreturn |
| ; CHECK: define void @mustprogress_store( |
| ; |
| entry: |
| br label %while.body |
| |
| while.body: |
| store i32 0, i32* %ptr |
| br label %while.body |
| } |
| |
| declare void @unknown_fn() |
| |
| define void @mustprogress_call_unknown_fn() mustprogress { |
| ; CHECK-NOT: Function Attrs: {{.*}} willreturn |
| ; CHECK: define void @mustprogress_call_unknown_fn( |
| ; |
| call void @unknown_fn() |
| ret void |
| } |
| |
| define i32 @mustprogress_call_known_functions(i32* %ptr) mustprogress { |
| ; CHECK: Function Attrs: {{.*}} readonly willreturn |
| ; CHECK-NEXT: define i32 @mustprogress_call_known_functions( |
| ; |
| call void @mustprogress_readnone() |
| %r = call i32 @mustprogress_load(i32* %ptr) |
| ret i32 %r |
| } |
| |
| declare i32 @__gxx_personality_v0(...) |
| |
| define i64 @mustprogress_mayunwind() mustprogress personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { |
| ; CHECK: Function Attrs: {{.*}} readnone willreturn |
| ; CHECK-NEXT: define i64 @mustprogress_mayunwind( |
| ; |
| %a = invoke i64 @fn_noread() |
| to label %A unwind label %B |
| A: |
| ret i64 10 |
| |
| B: |
| %val = landingpad { i8*, i32 } |
| catch i8* null |
| ret i64 0 |
| } |
| |
| ; Function without loops or non-willreturn calls will return. |
| define void @willreturn_no_loop(i1 %c, i32* %p) { |
| ; CHECK: Function Attrs: mustprogress willreturn |
| ; CHECK-NEXT: define void @willreturn_no_loop( |
| ; |
| br i1 %c, label %if, label %else |
| |
| if: |
| load atomic i32, i32* %p seq_cst, align 4 |
| call void @fn_willreturn() |
| br label %end |
| |
| else: |
| store atomic i32 0, i32* %p seq_cst, align 4 |
| br label %end |
| |
| end: |
| ret void |
| } |
| |
| ; Calls a function that is not guaranteed to return, not willreturn. |
| define void @willreturn_non_returning_function(i1 %c, i32* %p) { |
| ; CHECK-NOT: Function Attrs: {{.*}}willreturn |
| ; CHECK: define void @willreturn_non_returning_function( |
| ; |
| call void @unknown_fn() |
| ret void |
| } |
| |
| ; Infinite loop without mustprogress, will not return. |
| define void @willreturn_loop() { |
| ; CHECK-NOT: Function Attrs: {{.*}}willreturn |
| ; CHECK: define void @willreturn_loop( |
| ; |
| br label %loop |
| |
| loop: |
| br label %loop |
| } |
| |
| ; Finite loop. Could be willreturn but not detected. |
| ; FIXME |
| define void @willreturn_finite_loop() { |
| ; CHECK-NOT: Function Attrs: {{.*}}willreturn |
| ; CHECK: define void @willreturn_finite_loop( |
| ; |
| entry: |
| br label %loop |
| |
| loop: |
| %i = phi i32 [ 0, %entry], [ %i.inc, %loop ] |
| %i.inc = add nuw i32 %i, 1 |
| %c = icmp ne i32 %i.inc, 100 |
| br i1 %c, label %loop, label %end |
| |
| end: |
| ret void |
| } |
| |
| ; Infinite recursion without mustprogress, will not return. |
| define void @willreturn_recursion() { |
| ; CHECK-NOT: Function Attrs: {{.*}}willreturn |
| ; CHECK: define void @willreturn_recursion( |
| ; |
| tail call void @willreturn_recursion() |
| ret void |
| } |
| |
| ; Irreducible infinite loop, will not return. |
| define void @willreturn_irreducible(i1 %c) { |
| ; CHECK-NOT: Function Attrs: {{.*}}willreturn |
| ; CHECK: define void @willreturn_irreducible( |
| ; |
| br i1 %c, label %bb1, label %bb2 |
| |
| bb1: |
| br label %bb2 |
| |
| bb2: |
| br label %bb1 |
| } |
| |
| define linkonce i32 @square(i32) { |
| ; CHECK-NOT: Function Attrs: {{.*}}willreturn |
| ; CHECK: define linkonce i32 @square( |
| %2 = mul nsw i32 %0, %0 |
| ret i32 %2 |
| } |
| |
| declare i64 @fn_noread() readnone |
| declare void @fn_willreturn() willreturn |