1; RUN: opt -function-attrs -S %s | FileCheck %s
2
3define void @mustprogress_readnone() mustprogress {
4; CHECK:      Function Attrs: {{.*}} noreturn {{.*}} readnone willreturn
5; CHECK-NEXT: define void @mustprogress_readnone()
6;
7entry:
8  br label %while.body
9
10while.body:
11  br label %while.body
12}
13
14define i32 @mustprogress_load(i32* %ptr) mustprogress {
15; CHECK:      Function Attrs: {{.*}} readonly willreturn
16; CHECK-NEXT: define i32 @mustprogress_load(
17;
18entry:
19  br label %while.body
20
21while.body:
22  %r = load i32, i32* %ptr
23  br label %while.body
24}
25
26define void @mustprogress_store(i32* %ptr) mustprogress {
27; CHECK-NOT: Function Attrs: {{.*}} willreturn
28; CHECK: define void @mustprogress_store(
29;
30entry:
31  br label %while.body
32
33while.body:
34  store i32 0, i32* %ptr
35  br label %while.body
36}
37
38declare void @unknown_fn()
39
40define void @mustprogress_call_unknown_fn() mustprogress {
41; CHECK-NOT: Function Attrs: {{.*}} willreturn
42; CHECK:     define void @mustprogress_call_unknown_fn(
43;
44  call void @unknown_fn()
45  ret void
46}
47
48define i32 @mustprogress_call_known_functions(i32* %ptr) mustprogress {
49; CHECK:      Function Attrs: {{.*}} readonly willreturn
50; CHECK-NEXT: define i32 @mustprogress_call_known_functions(
51;
52  call void @mustprogress_readnone()
53  %r = call i32 @mustprogress_load(i32* %ptr)
54  ret i32 %r
55}
56
57declare i32 @__gxx_personality_v0(...)
58
59define i64 @mustprogress_mayunwind() mustprogress personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
60; CHECK:      Function Attrs: {{.*}} readnone willreturn
61; CHECK-NEXT: define i64 @mustprogress_mayunwind(
62;
63  %a = invoke i64 @fn_noread()
64          to label %A unwind label %B
65A:
66  ret i64 10
67
68B:
69  %val = landingpad { i8*, i32 }
70           catch i8* null
71  ret i64 0
72}
73
74; Function without loops or non-willreturn calls will return.
75define void @willreturn_no_loop(i1 %c, i32* %p) {
76; CHECK: Function Attrs: mustprogress willreturn
77; CHECK-NEXT: define void @willreturn_no_loop(
78;
79  br i1 %c, label %if, label %else
80
81if:
82  load atomic i32, i32* %p seq_cst, align 4
83  call void @fn_willreturn()
84  br label %end
85
86else:
87  store atomic i32 0, i32* %p seq_cst, align 4
88  br label %end
89
90end:
91  ret void
92}
93
94; Calls a function that is not guaranteed to return, not willreturn.
95define void @willreturn_non_returning_function(i1 %c, i32* %p) {
96; CHECK-NOT: Function Attrs: {{.*}}willreturn
97; CHECK: define void @willreturn_non_returning_function(
98;
99  call void @unknown_fn()
100  ret void
101}
102
103; Infinite loop without mustprogress, will not return.
104define void @willreturn_loop() {
105; CHECK-NOT: Function Attrs: {{.*}}willreturn
106; CHECK: define void @willreturn_loop(
107;
108  br label %loop
109
110loop:
111  br label %loop
112}
113
114; Finite loop. Could be willreturn but not detected.
115; FIXME
116define void @willreturn_finite_loop() {
117; CHECK-NOT: Function Attrs: {{.*}}willreturn
118; CHECK: define void @willreturn_finite_loop(
119;
120entry:
121  br label %loop
122
123loop:
124  %i = phi i32 [ 0, %entry], [ %i.inc, %loop ]
125  %i.inc = add nuw i32 %i, 1
126  %c = icmp ne i32 %i.inc, 100
127  br i1 %c, label %loop, label %end
128
129end:
130  ret void
131}
132
133; Infinite recursion without mustprogress, will not return.
134define void @willreturn_recursion() {
135; CHECK-NOT: Function Attrs: {{.*}}willreturn
136; CHECK: define void @willreturn_recursion(
137;
138  tail call void @willreturn_recursion()
139  ret void
140}
141
142; Irreducible infinite loop, will not return.
143define void @willreturn_irreducible(i1 %c) {
144; CHECK-NOT: Function Attrs: {{.*}}willreturn
145; CHECK: define void @willreturn_irreducible(
146;
147  br i1 %c, label %bb1, label %bb2
148
149bb1:
150  br label %bb2
151
152bb2:
153  br label %bb1
154}
155
156define linkonce i32 @square(i32) {
157; CHECK-NOT: Function Attrs: {{.*}}willreturn
158; CHECK: define linkonce i32 @square(
159    %2 = mul nsw i32 %0, %0
160    ret i32 %2
161}
162
163declare i64 @fn_noread() readnone
164declare void @fn_willreturn() willreturn
165