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