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