1; RUN: opt < %s -basicaa -functionattrs -rpo-functionattrs -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()
28  ret i32 %a
29}
30
31; CHECK: Function Attrs
32; CHECK-SAME: convergent
33; CHECK-NEXT: define i32 @call_extern()
34define i32 @call_extern() convergent {
35  %a = call i32 @extern()
36  ret i32 %a
37}
38
39; CHECK: Function Attrs
40; CHECK-SAME: convergent
41; CHECK-NEXT: declare void @llvm.cuda.syncthreads()
42declare void @llvm.cuda.syncthreads() convergent
43
44; CHECK: Function Attrs
45; CHECK-SAME: convergent
46; CHECK-NEXT: define i32 @intrinsic()
47define i32 @intrinsic() convergent {
48  call void @llvm.cuda.syncthreads()
49  ret i32 0
50}
51
52@xyz = global i32 ()* null
53; CHECK: Function Attrs
54; CHECK-SAME: convergent
55; CHECK-NEXT: define i32 @functionptr()
56define i32 @functionptr() convergent {
57  %1 = load i32 ()*, i32 ()** @xyz
58  %2 = call i32 %1()
59  ret i32 %2
60}
61
62; CHECK: Function Attrs
63; CHECK-NOT: convergent
64; CHECK-NEXT: define i32 @recursive1()
65define i32 @recursive1() convergent {
66  %a = call i32 @recursive2()
67  ret i32 %a
68}
69
70; CHECK: Function Attrs
71; CHECK-NOT: convergent
72; CHECK-NEXT: define i32 @recursive2()
73define i32 @recursive2() convergent {
74  %a = call i32 @recursive1()
75  ret i32 %a
76}
77
78; CHECK: Function Attrs
79; CHECK-SAME: convergent
80; CHECK-NEXT: define i32 @noopt()
81define i32 @noopt() convergent optnone noinline {
82  %a = call i32 @noopt_friend()
83  ret i32 0
84}
85
86; A function which is mutually-recursive with a convergent, optnone function
87; shouldn't have its convergent attribute stripped.
88; CHECK: Function Attrs
89; CHECK-SAME: convergent
90; CHECK-NEXT: define i32 @noopt_friend()
91define i32 @noopt_friend() convergent {
92  %a = call i32 @noopt()
93  ret i32 0
94}
95