blob: bc21d85ec2208e3c88b8142df0a0066cd71826e1 [file] [log] [blame]
Justin Lebar9d943972016-03-14 20:18:54 +00001; RUN: opt -functionattrs -S < %s | FileCheck %s
Justin Lebar260854b2016-02-09 23:03:22 +00002
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 {
Justin Lebar9d943972016-03-14 20:18:54 +000027 %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 {
Justin Lebar260854b2016-02-09 23:03:22 +000038 %a = call i32 @k()
39 ret i32 %a
40}
41
42; CHECK: Function Attrs
43; CHECK-SAME: convergent
Justin Lebar9d943972016-03-14 20:18:54 +000044; 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
Justin Lebar260854b2016-02-09 23:03:22 +000058}
59
60; CHECK: Function Attrs
61; CHECK-SAME: convergent
62; CHECK-NEXT: declare void @llvm.cuda.syncthreads()
63declare void @llvm.cuda.syncthreads() convergent
64
65; CHECK: Function Attrs
66; CHECK-SAME: convergent
67; CHECK-NEXT: define i32 @intrinsic()
68define i32 @intrinsic() convergent {
Justin Lebar9d943972016-03-14 20:18:54 +000069 ; Implicitly convergent, because the intrinsic is convergent.
Justin Lebar260854b2016-02-09 23:03:22 +000070 call void @llvm.cuda.syncthreads()
71 ret i32 0
72}
73
Justin Lebar260854b2016-02-09 23:03:22 +000074; CHECK: Function Attrs
75; CHECK-NOT: convergent
76; CHECK-NEXT: define i32 @recursive1()
77define i32 @recursive1() convergent {
Justin Lebar9d943972016-03-14 20:18:54 +000078 %a = call i32 @recursive2() convergent
Justin Lebar260854b2016-02-09 23:03:22 +000079 ret i32 %a
80}
81
82; CHECK: Function Attrs
83; CHECK-NOT: convergent
84; CHECK-NEXT: define i32 @recursive2()
85define i32 @recursive2() convergent {
Justin Lebar9d943972016-03-14 20:18:54 +000086 %a = call i32 @recursive1() convergent
Justin Lebar260854b2016-02-09 23:03:22 +000087 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 {
Justin Lebar9d943972016-03-14 20:18:54 +000094 %a = call i32 @noopt_friend() convergent
Justin Lebar260854b2016-02-09 23:03:22 +000095 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}