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
5 define void @mustprogress_readnone() mustprogress {
6 ; FNATTRS: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
7 ; FNATTRS-LABEL: @mustprogress_readnone(
9 ; FNATTRS-NEXT: br label [[WHILE_BODY:%.*]]
10 ; FNATTRS: while.body:
11 ; FNATTRS-NEXT: br label [[WHILE_BODY]]
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]]
27 define 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]]
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]]
48 %r = load i32, ptr %ptr
52 define void @mustprogress_store(ptr %ptr) mustprogress {
53 ; COMMON: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write)
54 ; COMMON-LABEL: @mustprogress_store(
56 ; COMMON-NEXT: br label [[WHILE_BODY:%.*]]
58 ; COMMON-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
59 ; COMMON-NEXT: br label [[WHILE_BODY]]
69 declare void @unknown_fn()
71 define 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
77 call void @unknown_fn()
81 define 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]]
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 nocapture nofree readonly [[PTR:%.*]]) #[[ATTR12:[0-9]+]]
92 ; ATTRIBUTOR-NEXT: ret i32 [[R]]
94 call void @mustprogress_readnone()
95 %r = call i32 @mustprogress_load(ptr %ptr)
99 declare i32 @__gxx_personality_v0(...)
101 define 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:%.*]]
107 ; FNATTRS-NEXT: ret i64 10
109 ; FNATTRS-NEXT: [[VAL:%.*]] = landingpad { ptr, i32 }
110 ; FNATTRS-NEXT: catch ptr null
111 ; FNATTRS-NEXT: ret i64 0
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:%.*]]
118 ; ATTRIBUTOR-NEXT: ret i64 10
120 ; ATTRIBUTOR-NEXT: [[VAL:%.*]] = landingpad { ptr, i32 }
121 ; ATTRIBUTOR-NEXT: catch ptr null
122 ; ATTRIBUTOR-NEXT: ret i64 0
124 %a = invoke i64 @fn_noread()
125 to label %A unwind label %B
130 %val = landingpad { ptr, i32 }
135 ; Function without loops or non-willreturn calls will return.
136 define 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:%.*]]
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:%.*]]
145 ; FNATTRS-NEXT: store atomic i32 0, ptr [[P]] seq_cst, align 4
146 ; FNATTRS-NEXT: br label [[END]]
148 ; FNATTRS-NEXT: ret void
150 ; ATTRIBUTOR: Function Attrs: mustprogress willreturn
151 ; ATTRIBUTOR-LABEL: @willreturn_no_loop(
152 ; ATTRIBUTOR-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
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:%.*]]
158 ; ATTRIBUTOR-NEXT: store atomic i32 0, ptr [[P]] seq_cst, align 4
159 ; ATTRIBUTOR-NEXT: br label [[END]]
161 ; ATTRIBUTOR-NEXT: ret void
163 br i1 %c, label %if, label %else
166 load atomic i32, ptr %p seq_cst, align 4
167 call void @fn_willreturn()
171 store atomic i32 0, ptr %p seq_cst, align 4
178 ; Calls a function that is not guaranteed to return, not willreturn.
179 define 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
184 call void @unknown_fn()
188 ; Infinite loop without mustprogress, will not return.
189 define 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:%.*]]
194 ; COMMON-NEXT: br label [[LOOP]]
202 ; Finite loop. Could be willreturn but not detected.
204 define 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:%.*]]
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:%.*]]
215 ; COMMON-NEXT: ret void
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
230 ; Infinite recursion without mustprogress, will not return.
231 define 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
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
242 tail call void @willreturn_recursion()
246 ; Irreducible infinite loop, will not return.
247 define 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:%.*]]
252 ; COMMON-NEXT: br label [[BB2]]
254 ; COMMON-NEXT: br label [[BB1]]
256 br i1 %c, label %bb1, label %bb2
265 define linkonce i32 @square(i32) {
266 ; COMMON-LABEL: @square(
267 ; COMMON-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], [[TMP0]]
268 ; COMMON-NEXT: ret i32 [[TMP2]]
270 %2 = mul nsw i32 %0, %0
274 declare i64 @fn_noread() readnone
275 declare void @fn_willreturn() willreturn