1 ; RUN: opt -functionattrs -S < %s | FileCheck %s 2 3 ; CHECK: Function Attrs 4 ; CHECK-NOT: convergent 5 ; CHECK-NEXT: define i32 @nonleaf() 6 define i32 @nonleaf() convergent { 7 %a = call i32 @leaf() 8 ret i32 %a 9 } 10 11 ; CHECK: Function Attrs 12 ; CHECK-NOT: convergent 13 ; CHECK-NEXT: define i32 @leaf() 14 define i32 @leaf() convergent { 15 ret i32 0 16 } 17 18 ; CHECK: Function Attrs 19 ; CHECK-SAME: convergent 20 ; CHECK-NEXT: declare i32 @k() 21 declare i32 @k() convergent 22 23 ; CHECK: Function Attrs 24 ; CHECK-SAME: convergent 25 ; CHECK-NEXT: define i32 @extern() 26 define i32 @extern() convergent { 27 %a = call i32 @k() convergent 28 ret i32 %a 29 } 30 31 ; Convergent should not be removed on the function here. Although the call is 32 ; not explicitly convergent, it picks up the convergent attr from the callee. 33 ; 34 ; CHECK: Function Attrs 35 ; CHECK-SAME: convergent 36 ; CHECK-NEXT: define i32 @extern_non_convergent_call() 37 define i32 @extern_non_convergent_call() convergent { 38 %a = call i32 @k() 39 ret i32 %a 40 } 41 42 ; CHECK: Function Attrs 43 ; CHECK-SAME: convergent 44 ; CHECK-NEXT: define i32 @indirect_convergent_call( 45 define i32 @indirect_convergent_call(i32 ()* %f) convergent { 46 %a = call i32 %f() convergent 47 ret i32 %a 48 } 49 ; Give indirect_non_convergent_call the norecurse attribute so we get a 50 ; "Function Attrs" comment in the output. 51 ; 52 ; CHECK: Function Attrs 53 ; CHECK-NOT: convergent 54 ; CHECK-NEXT: define i32 @indirect_non_convergent_call( 55 define i32 @indirect_non_convergent_call(i32 ()* %f) convergent norecurse { 56 %a = call i32 %f() 57 ret i32 %a 58 } 59 60 ; CHECK: Function Attrs 61 ; CHECK-SAME: convergent 62 ; CHECK-NEXT: declare void @llvm.nvvm.barrier0() 63 declare void @llvm.nvvm.barrier0() convergent 64 65 ; CHECK: Function Attrs 66 ; CHECK-SAME: convergent 67 ; CHECK-NEXT: define i32 @intrinsic() 68 define i32 @intrinsic() convergent { 69 ; Implicitly convergent, because the intrinsic is convergent. 70 call void @llvm.nvvm.barrier0() 71 ret i32 0 72 } 73 74 ; CHECK: Function Attrs 75 ; CHECK-NOT: convergent 76 ; CHECK-NEXT: define i32 @recursive1() 77 define i32 @recursive1() convergent { 78 %a = call i32 @recursive2() convergent 79 ret i32 %a 80 } 81 82 ; CHECK: Function Attrs 83 ; CHECK-NOT: convergent 84 ; CHECK-NEXT: define i32 @recursive2() 85 define i32 @recursive2() convergent { 86 %a = call i32 @recursive1() convergent 87 ret i32 %a 88 } 89 90 ; CHECK: Function Attrs 91 ; CHECK-SAME: convergent 92 ; CHECK-NEXT: define i32 @noopt() 93 define i32 @noopt() convergent optnone noinline { 94 %a = call i32 @noopt_friend() convergent 95 ret i32 0 96 } 97 98 ; A function which is mutually-recursive with a convergent, optnone function 99 ; shouldn't have its convergent attribute stripped. 100 ; CHECK: Function Attrs 101 ; CHECK-SAME: convergent 102 ; CHECK-NEXT: define i32 @noopt_friend() 103 define i32 @noopt_friend() convergent { 104 %a = call i32 @noopt() 105 ret i32 0 106 } 107