1; RUN: opt -functionattrs -S < %s | FileCheck %s 2 3; CHECK: Function Attrs 4; CHECK-NOT: convergent 5; CHECK-NEXT: define i32 @nonleaf() 6define 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() 14define i32 @leaf() convergent { 15 ret i32 0 16} 17 18; CHECK: Function Attrs 19; CHECK-SAME: convergent 20; CHECK-NEXT: declare i32 @k() 21declare i32 @k() convergent 22 23; CHECK: Function Attrs 24; CHECK-SAME: convergent 25; CHECK-NEXT: define i32 @extern() 26define 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() 37define 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( 45define 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( 55define 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() 63declare void @llvm.nvvm.barrier0() convergent 64 65; CHECK: Function Attrs 66; CHECK-SAME: convergent 67; CHECK-NEXT: define i32 @intrinsic() 68define 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() 77define 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() 85define 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() 93define 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() 103define i32 @noopt_friend() convergent { 104 %a = call i32 @noopt() 105 ret i32 0 106} 107