xref: /llvm-project/llvm/test/Transforms/FunctionAttrs/willreturn.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes
2; RUN: opt -passes=function-attrs -S %s | FileCheck --check-prefixes=COMMON,FNATTRS %s
3; RUN: opt -passes=attributor-light -S %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s
4
5define void @mustprogress_readnone() mustprogress {
6; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
7; FNATTRS-LABEL: @mustprogress_readnone(
8; FNATTRS-NEXT:  entry:
9; FNATTRS-NEXT:    br label [[WHILE_BODY:%.*]]
10; FNATTRS:       while.body:
11; FNATTRS-NEXT:    br label [[WHILE_BODY]]
12;
13; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(none)
14; ATTRIBUTOR-LABEL: @mustprogress_readnone(
15; ATTRIBUTOR-NEXT:  entry:
16; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY:%.*]]
17; ATTRIBUTOR:       while.body:
18; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY]]
19;
20entry:
21  br label %while.body
22
23while.body:
24  br label %while.body
25}
26
27define i32 @mustprogress_load(ptr %ptr) mustprogress {
28; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read)
29; FNATTRS-LABEL: @mustprogress_load(
30; FNATTRS-NEXT:  entry:
31; FNATTRS-NEXT:    br label [[WHILE_BODY:%.*]]
32; FNATTRS:       while.body:
33; FNATTRS-NEXT:    [[R:%.*]] = load i32, ptr [[PTR:%.*]], align 4
34; FNATTRS-NEXT:    br label [[WHILE_BODY]]
35;
36; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: read)
37; ATTRIBUTOR-LABEL: @mustprogress_load(
38; ATTRIBUTOR-NEXT:  entry:
39; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY:%.*]]
40; ATTRIBUTOR:       while.body:
41; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i32, ptr [[PTR:%.*]], align 4
42; ATTRIBUTOR-NEXT:    br label [[WHILE_BODY]]
43;
44entry:
45  br label %while.body
46
47while.body:
48  %r = load i32, ptr %ptr
49  br label %while.body
50}
51
52define void @mustprogress_store(ptr %ptr) mustprogress {
53; COMMON: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write)
54; COMMON-LABEL: @mustprogress_store(
55; COMMON-NEXT:  entry:
56; COMMON-NEXT:    br label [[WHILE_BODY:%.*]]
57; COMMON:       while.body:
58; COMMON-NEXT:    store i32 0, ptr [[PTR:%.*]], align 4
59; COMMON-NEXT:    br label [[WHILE_BODY]]
60;
61entry:
62  br label %while.body
63
64while.body:
65  store i32 0, ptr %ptr
66  br label %while.body
67}
68
69declare void @unknown_fn()
70
71define void @mustprogress_call_unknown_fn() mustprogress {
72; COMMON: Function Attrs: mustprogress
73; COMMON-LABEL: @mustprogress_call_unknown_fn(
74; COMMON-NEXT:    call void @unknown_fn()
75; COMMON-NEXT:    ret void
76;
77  call void @unknown_fn()
78  ret void
79}
80
81define i32 @mustprogress_call_known_functions(ptr %ptr) mustprogress {
82; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read)
83; FNATTRS-LABEL: @mustprogress_call_known_functions(
84; FNATTRS-NEXT:    call void @mustprogress_readnone()
85; FNATTRS-NEXT:    [[R:%.*]] = call i32 @mustprogress_load(ptr [[PTR:%.*]])
86; FNATTRS-NEXT:    ret i32 [[R]]
87;
88; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
89; ATTRIBUTOR-LABEL: @mustprogress_call_known_functions(
90; ATTRIBUTOR-NEXT:    call void @mustprogress_readnone() #[[ATTR9:[0-9]+]]
91; ATTRIBUTOR-NEXT:    [[R:%.*]] = call i32 @mustprogress_load(ptr nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR12:[0-9]+]]
92; ATTRIBUTOR-NEXT:    ret i32 [[R]]
93;
94  call void @mustprogress_readnone()
95  %r = call i32 @mustprogress_load(ptr %ptr)
96  ret i32 %r
97}
98
99declare i32 @__gxx_personality_v0(...)
100
101define i64 @mustprogress_mayunwind() mustprogress personality ptr @__gxx_personality_v0 {
102; FNATTRS: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
103; FNATTRS-LABEL: @mustprogress_mayunwind(
104; FNATTRS-NEXT:    [[A:%.*]] = invoke i64 @fn_noread()
105; FNATTRS-NEXT:            to label [[A:%.*]] unwind label [[B:%.*]]
106; FNATTRS:       A:
107; FNATTRS-NEXT:    ret i64 10
108; FNATTRS:       B:
109; FNATTRS-NEXT:    [[VAL:%.*]] = landingpad { ptr, i32 }
110; FNATTRS-NEXT:            catch ptr null
111; FNATTRS-NEXT:    ret i64 0
112;
113; ATTRIBUTOR: Function Attrs: mustprogress nosync nounwind willreturn memory(none)
114; ATTRIBUTOR-LABEL: @mustprogress_mayunwind(
115; ATTRIBUTOR-NEXT:    [[A:%.*]] = invoke i64 @fn_noread() #[[ATTR13:[0-9]+]]
116; ATTRIBUTOR-NEXT:            to label [[A:%.*]] unwind label [[B:%.*]]
117; ATTRIBUTOR:       A:
118; ATTRIBUTOR-NEXT:    ret i64 10
119; ATTRIBUTOR:       B:
120; ATTRIBUTOR-NEXT:    [[VAL:%.*]] = landingpad { ptr, i32 }
121; ATTRIBUTOR-NEXT:            catch ptr null
122; ATTRIBUTOR-NEXT:    ret i64 0
123;
124  %a = invoke i64 @fn_noread()
125  to label %A unwind label %B
126A:
127  ret i64 10
128
129B:
130  %val = landingpad { ptr, i32 }
131  catch ptr null
132  ret i64 0
133}
134
135; Function without loops or non-willreturn calls will return.
136define void @willreturn_no_loop(i1 %c, ptr %p) {
137; FNATTRS: Function Attrs: mustprogress willreturn
138; FNATTRS-LABEL: @willreturn_no_loop(
139; FNATTRS-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
140; FNATTRS:       if:
141; FNATTRS-NEXT:    [[TMP1:%.*]] = load atomic i32, ptr [[P:%.*]] seq_cst, align 4
142; FNATTRS-NEXT:    call void @fn_willreturn()
143; FNATTRS-NEXT:    br label [[END:%.*]]
144; FNATTRS:       else:
145; FNATTRS-NEXT:    store atomic i32 0, ptr [[P]] seq_cst, align 4
146; FNATTRS-NEXT:    br label [[END]]
147; FNATTRS:       end:
148; FNATTRS-NEXT:    ret void
149;
150; ATTRIBUTOR: Function Attrs: mustprogress willreturn
151; ATTRIBUTOR-LABEL: @willreturn_no_loop(
152; ATTRIBUTOR-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
153; ATTRIBUTOR:       if:
154; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = load atomic i32, ptr [[P:%.*]] seq_cst, align 4
155; ATTRIBUTOR-NEXT:    call void @fn_willreturn() #[[ATTR11:[0-9]+]]
156; ATTRIBUTOR-NEXT:    br label [[END:%.*]]
157; ATTRIBUTOR:       else:
158; ATTRIBUTOR-NEXT:    store atomic i32 0, ptr [[P]] seq_cst, align 4
159; ATTRIBUTOR-NEXT:    br label [[END]]
160; ATTRIBUTOR:       end:
161; ATTRIBUTOR-NEXT:    ret void
162;
163  br i1 %c, label %if, label %else
164
165if:
166  load atomic i32, ptr %p seq_cst, align 4
167  call void @fn_willreturn()
168  br label %end
169
170else:
171  store atomic i32 0, ptr %p seq_cst, align 4
172  br label %end
173
174end:
175  ret void
176}
177
178; Calls a function that is not guaranteed to return, not willreturn.
179define void @willreturn_non_returning_function(i1 %c, ptr %p) {
180; COMMON-LABEL: @willreturn_non_returning_function(
181; COMMON-NEXT:    call void @unknown_fn()
182; COMMON-NEXT:    ret void
183;
184  call void @unknown_fn()
185  ret void
186}
187
188; Infinite loop without mustprogress, will not return.
189define void @willreturn_loop() {
190; COMMON: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none)
191; COMMON-LABEL: @willreturn_loop(
192; COMMON-NEXT:    br label [[LOOP:%.*]]
193; COMMON:       loop:
194; COMMON-NEXT:    br label [[LOOP]]
195;
196  br label %loop
197
198loop:
199  br label %loop
200}
201
202; Finite loop. Could be willreturn but not detected.
203; FIXME
204define void @willreturn_finite_loop() {
205; COMMON: Function Attrs: nofree norecurse nosync nounwind memory(none)
206; COMMON-LABEL: @willreturn_finite_loop(
207; COMMON-NEXT:  entry:
208; COMMON-NEXT:    br label [[LOOP:%.*]]
209; COMMON:       loop:
210; COMMON-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LOOP]] ]
211; COMMON-NEXT:    [[I_INC]] = add nuw i32 [[I]], 1
212; COMMON-NEXT:    [[C:%.*]] = icmp ne i32 [[I_INC]], 100
213; COMMON-NEXT:    br i1 [[C]], label [[LOOP]], label [[END:%.*]]
214; COMMON:       end:
215; COMMON-NEXT:    ret void
216;
217entry:
218  br label %loop
219
220loop:
221  %i = phi i32 [ 0, %entry], [ %i.inc, %loop ]
222  %i.inc = add nuw i32 %i, 1
223  %c = icmp ne i32 %i.inc, 100
224  br i1 %c, label %loop, label %end
225
226end:
227  ret void
228}
229
230; Infinite recursion without mustprogress, will not return.
231define void @willreturn_recursion() {
232; FNATTRS: Function Attrs: nofree nosync nounwind memory(none)
233; FNATTRS-LABEL: @willreturn_recursion(
234; FNATTRS-NEXT:    tail call void @willreturn_recursion()
235; FNATTRS-NEXT:    ret void
236;
237; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(none)
238; ATTRIBUTOR-LABEL: @willreturn_recursion(
239; ATTRIBUTOR-NEXT:    tail call void @willreturn_recursion() #[[ATTR9]]
240; ATTRIBUTOR-NEXT:    ret void
241;
242  tail call void @willreturn_recursion()
243  ret void
244}
245
246; Irreducible infinite loop, will not return.
247define void @willreturn_irreducible(i1 %c) {
248; COMMON: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none)
249; COMMON-LABEL: @willreturn_irreducible(
250; COMMON-NEXT:    br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
251; COMMON:       bb1:
252; COMMON-NEXT:    br label [[BB2]]
253; COMMON:       bb2:
254; COMMON-NEXT:    br label [[BB1]]
255;
256  br i1 %c, label %bb1, label %bb2
257
258bb1:
259  br label %bb2
260
261bb2:
262  br label %bb1
263}
264
265define linkonce i32 @square(i32) {
266; COMMON-LABEL: @square(
267; COMMON-NEXT:    [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], [[TMP0]]
268; COMMON-NEXT:    ret i32 [[TMP2]]
269;
270  %2 = mul nsw i32 %0, %0
271  ret i32 %2
272}
273
274declare i64 @fn_noread() readnone
275declare void @fn_willreturn() willreturn
276