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