[InstCombine] Signed saturation patterns
[llvm-complete.git] / test / Transforms / FunctionAttrs / willreturn.ll
blob2528382d9bd4f91909cffcd5f3143661f37c004a
1 ; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR
2 ; RUN: opt -passes=attributor --attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefix=ATTRIBUTOR
5 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7 ; Test cases specifically designed for the "willreturn" function attribute.
8 ; We use FIXME's to indicate problems and missing attributes.
11 ; TEST 1 (positive case)
12 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
13 ; FNATTR-NEXT: define void @only_return()
14 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
15 ; ATTRIBUTOR-NEXT: define void @only_return()
16 define void @only_return() #0 {
17     ret void
21 ; TEST 2 (positive & negative case)
22 ; 2.1 (positive case)
23 ; recursive function which will halt
24 ; int fib(int n){
25 ;    return n<=1? n : fib(n-1) + fib(n-2);
26 ; }
28 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
29 ; FNATTR-NEXT: define i32 @fib(i32 %0)
30 ; FIXME: missing willreturn
31 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
32 ; ATTRIBUTOR-NEXT: define i32 @fib(i32 %0) local_unnamed_addr
33 define i32 @fib(i32 %0) local_unnamed_addr #0 {
34   %2 = icmp slt i32 %0, 2
35   br i1 %2, label %9, label %3
37 ; <label>:3:                                      ; preds = %1
38   %4 = add nsw i32 %0, -1
39   %5 = tail call i32 @fib(i32 %4)
40   %6 = add nsw i32 %0, -2
41   %7 = tail call i32 @fib(i32 %6)
42   %8 = add nsw i32 %7, %5
43   ret i32 %8
45 ; <label>:9:                                      ; preds = %1
46   ret i32 %0
49 ; 2.2 (negative case)
50 ; recursive function which doesn't stop for some input.
51 ; int fact_maybe_not_halt(int n) {
52 ;   if (n==0) {
53 ;     return 1;
54 ;   }
55 ;   return fact_maybe_not_halt( n > 0 ? n-1 : n) * n;
56 ; }
57 ; fact_maybe_not(-1) doesn't stop.
59 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
60 ; FNATTR-NOT: willreturn
61 ; FNATTR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
62 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
63 ; ATTRIBUTOR-NOT: willreturn
64 ; ATTRIBUTOR-NEXT: define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr
65 define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 {
66   %2 = icmp eq i32 %0, 0
67   br i1 %2, label %11, label %3
69 ; <label>:3:                                      ; preds = %1, %3
70   %4 = phi i32 [ %8, %3 ], [ %0, %1 ]
71   %5 = phi i32 [ %9, %3 ], [ 1, %1 ]
72   %6 = icmp sgt i32 %4, 0
73   %7 = sext i1 %6 to i32
74   %8 = add nsw i32 %4, %7
75   %9 = mul nsw i32 %4, %5
76   %10 = icmp eq i32 %8, 0
77   br i1 %10, label %11, label %3
79 ; <label>:11:                                     ; preds = %3, %1
80   %12 = phi i32 [ 1, %1 ], [ %9, %3 ]
81   ret i32 %12
85 ; TEST 3 (positive case)
86 ; loop
87 ; int fact_loop(int n ){
88 ;   int ans = 1;
89 ;   for(int i = 1;i<=n;i++){
90 ;     ans *= i;
91 ;   }
92 ;   return ans;
93 ; }
95 ; FIXME: missing willreturn
96 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
97 ; FNATTR-NEXT: define i32 @fact_loop(i32 %0)
98 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
99 ; ATTRIBUTOR-NEXT: define i32 @fact_loop(i32 %0) local_unnamed_addr
100 define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
101   %2 = icmp slt i32 %0, 1
102   br i1 %2, label %3, label %5
104 ; <label>:3:                                      ; preds = %5, %1
105   %4 = phi i32 [ 1, %1 ], [ %8, %5 ]
106   ret i32 %4
108 ; <label>:5:                                      ; preds = %1, %5
109   %6 = phi i32 [ %9, %5 ], [ 1, %1 ]
110   %7 = phi i32 [ %8, %5 ], [ 1, %1 ]
111   %8 = mul nsw i32 %6, %7
112   %9 = add nuw nsw i32 %6, 1
113   %10 = icmp eq i32 %6, %0
114   br i1 %10, label %3, label %5
117 ; TEST 4 (negative case)
118 ; mutual recursion
119 ; void mutual_recursion1(){
120 ;    mutual_recursion2();
121 ; }
122 ; void mutual_recursion2(){
123 ;     mutual_recursion1();
124 ; }
126 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
127 ; FNATTR-NOT: willreturn
128 ; FNATTR-NEXT: define void @mutual_recursion1(i1 %c)
129 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
130 ; ATTRIBUTOR-NOT: willreturn
131 ; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c)
132 define void @mutual_recursion1(i1 %c) #0 {
133   br i1 %c, label %rec, label %end
134 rec:
135   call void @mutual_recursion2(i1 %c)
136   br label %end
137 end:
138   ret void
142 ; FNATTR: Function Attrs: noinline nounwind readnone uwtable
143 ; FNATTR-NOT: willreturn
144 ; FNATTR-NEXT: define void @mutual_recursion2(i1 %c)
145 ; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
146 ; ATTRIBUTOR-NOT: willreturn
147 ; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c)
148 define void @mutual_recursion2(i1 %c) #0 {
149   call void @mutual_recursion1(i1 %c)
150   ret void
154 ; TEST 5 (negative case)
155 ; call exit/abort (has noreturn attribute)
156 ; FNATTR: Function Attrs: noreturn
157 ; FNATTR-NEXT: declare void @exit(i32) local_unnamed_addr
158 ; ATTRIBUTOR: Function Attrs: noreturn
159 ; ATTRIBUTOR-NEXT: declare void @exit(i32) local_unnamed_add
160 declare void @exit(i32 %0) local_unnamed_addr noreturn
162 ; FNATTR: Function Attrs: noinline nounwind uwtable
163 ; FNATTR-NOT: willreturn
164 ; FNATTR-NEXT: define void @only_exit()
165 ; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
166 ; ATTRIBUTOR-NOT: willreturn
167 ; ATTRIBUTOR-NEXT: define void @only_exit() local_unnamed_addr
168 define void @only_exit() local_unnamed_addr #0 {
169   tail call void @exit(i32 0)
170   unreachable
173 ; conditional exit
174 ; void conditional_exit(int cond, int *p){
175 ;     if(cond){
176 ;       exit(0);
177 ;     }
178 ;     if(*p){
179 ;       exit(1);
180 ;     }
181 ;     return;
182 ; }
183 ; FNATTR: Function Attrs: noinline nounwind uwtable
184 ; FNATTR-NOT: willreturn
185 ; FNATTR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
186 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
187 ; ATTRIBUTOR-NOT: willreturn
188 ; ATTRIBUTOR-NEXT: define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
189 define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 {
190   %3 = icmp eq i32 %0, 0
191   br i1 %3, label %5, label %4
193 ; <label>:4:                                      ; preds = %2
194   tail call void @exit(i32 0)
195   unreachable
197 ; <label>:5:                                      ; preds = %2
198   %6 = load i32, i32* %1, align 4
199   %7 = icmp eq i32 %6, 0
200   br i1 %7, label %9, label %8
202 ; <label>:8:                                      ; preds = %5
203   tail call void @exit(i32 1)
204   unreachable
206 ; <label>:9:                                      ; preds = %5
207   ret void
210 ; TEST 6 (positive case)
211 ; Call intrinsic function
212 ; FIXME: missing willreturn
213 ; FNATTRS: Function Attrs: noinline readnone speculatable
214 ; FNATTRS-NEXT: declare float @llvm.floor.f32(float %0)
215 ; ATTRIBUTOR: Function Attrs: nounwind readnone speculatable
216 ; ATTRIBUTOR-NEXT: declare float @llvm.floor.f32(float)
217 declare float @llvm.floor.f32(float)
219 ; FNATTRS: Function Attrs: noinline nounwind readnone uwtable
220 ; FNATTRS-NEXT: define void @call_floor(float %a)
221 ; FIXME: missing willreturn
222 ; ATTRIBUTOR: Function Attrs: noinline nosync nounwind readnone uwtable
223 ; ATTRIBUTOR-NEXT: define void @call_floor(float %a)
224 define void @call_floor(float %a) #0 {
225     tail call float @llvm.floor.f32(float %a)
226     ret void
230 ; TEST 7 (negative case)
231 ; Call function declaration without willreturn
233 ; FNATTR: Function Attrs: noinline nounwind uwtable
234 ; FNATTR-NOT: willreturn
235 ; FNATTR-NEXT: declare void @maybe_noreturn()
236 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
237 ; ATTRIBUTOR-NOT: willreturn
238 ; ATTRIBUTOR-NEXT: declare void @maybe_noreturn()
239 declare void @maybe_noreturn() #0
241 ; FNATTR: Function Attrs: noinline nounwind uwtable
242 ; FNATTR-NOT: willreturn
243 ; FNATTR-NEXT: define void @call_maybe_noreturn()
244 ; ATTRIBUTOR: Function Attrs: noinline nounwind uwtable
245 ; ATTRIBUTOR-NOT: willreturn
246 ; ATTRIBUTOR-NEXT: define void @call_maybe_noreturn()
247 define void @call_maybe_noreturn() #0 {
248     tail call void @maybe_noreturn()
249     ret void
253 ; TEST 8 (positive case)
254 ; Check propagation.
256 ; FNATTR: Function Attrs: norecurse willreturn
257 ; FNATTR-NEXT: declare void @will_return()
258 ; ATTRIBUTOR: Function Attrs: norecurse willreturn
259 ; ATTRIBUTOR-NEXT: declare void @will_return()
260 declare void @will_return() willreturn norecurse
262 ; FNATTR: Function Attrs: noinline norecurse nounwind uwtable
263 ; FNATTR-NEXT: define void @f1()
264 ; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn
265 ; ATTRIBUTOR-NEXT: define void @f1()
266 define void @f1() #0 {
267     tail call void @will_return()
268     ret void
271 ; FNATTR: Function Attrs: noinline norecurse nounwind uwtable
272 ; FNATTR-NEXT: define void @f2()
273 ; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn
274 ; ATTRIBUTOR-NEXT: define void @f2()
275 define void @f2() #0 {
276     tail call void @f1()
277     ret void
281 ; TEST 9 (negative case)
282 ; call willreturn function in endless loop.
284 ; FNATTR: Function Attrs: noinline norecurse nounwind uwtable
285 ; FNATTR-NOT: willreturn
286 ; FNATTR-NEXT: define void @call_will_return_but_has_loop()
287 ; ATTRIBUTOR: Function Attrs: noinline norecurse noreturn nounwind uwtable
288 ; ATTRIBUTOR-NOT: willreturn
289 ; ATTRIBUTOR-NEXT: define void @call_will_return_but_has_loop()
290 define void @call_will_return_but_has_loop() #0 {
291   br label %label1
292 label1:
293   tail call void @will_return()
294   br label %label2
295 label2:
296   br label %label1
300 ; TEST 10 (positive case)
301 ; invoke a function with willreturn
303 ; FNATTR: Function Attrs: noinline uwtable willreturn
304 ; FNATTR-NEXT: declare i1 @maybe_raise_exception()
305 ; ATTRIBUTOR: Function Attrs: noinline uwtable willreturn
306 ; ATTRIBUTOR-NEXT: declare i1 @maybe_raise_exception()
307 declare i1 @maybe_raise_exception() #1 willreturn
309 ; FNATTR: Function Attrs: nounwind
310 ; FNATTR-NEXT: define void @invoke_test()
311 ; ATTRIBUTOR: Function Attrs: nounwind willreturn
312 ; ATTRIBUTOR-NEXT: define void @invoke_test()
313 define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 {
314   invoke i1 @maybe_raise_exception()
315       to label %N unwind label %F
316   N:
317     ret void
318   F:
319     %val = landingpad { i8*, i32 }
320                   catch i8* null
321     ret void
324 declare i32 @__gxx_personality_v0(...)
327 ; TEST 11 (positive case)
328 ; counstant trip count
329 ; int loop_constant_trip_count(int*p){
330 ;    int ans = 0;
331 ;    for(int i = 0;i<10;i++){
332 ;        ans += p[i];
333 ;    }
334 ;    return ans;
335 ; }
337 ; FIXME: missing willreturn
338 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
339 ; FNATTR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0)
340 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
341 ; ATTRIBUTOR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly %0)
342 define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 {
343   br label %3
345 ; <label>:2:                                      ; preds = %3
346   ret i32 %8
348 ; <label>:3:                                      ; preds = %3, %1
349   %4 = phi i64 [ 0, %1 ], [ %9, %3 ]
350   %5 = phi i32 [ 0, %1 ], [ %8, %3 ]
351   %6 = getelementptr inbounds i32, i32* %0, i64 %4
352   %7 = load i32, i32* %6, align 4
353   %8 = add nsw i32 %7, %5
354   %9 = add nuw nsw i64 %4, 1
355   %10 = icmp eq i64 %9, 10
356   br i1 %10, label %2, label %3
360 ; TEST 12 (negative case)
361 ; unbounded trip count
363 ; int loop_trip_count_unbound(unsigned s,unsigned e, int *p, int offset){
364 ;     int ans = 0;
365 ;     for(unsigned i = s;i != e;i+=offset){
366 ;         ans += p[i];
367 ;     }
368 ;     return ans;
369 ; }
370 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
371 ; FNATTR-NOT: willreturn
372 ; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
373 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
374 ; ATTRIBUTOR-NOT: willreturn
375 ; ATTRIBUTOR-NEXT: define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr
376 define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr #0 {
377   %5 = icmp eq i32 %0, %1
378   br i1 %5, label %6, label %8
380 ; <label>:6:                                      ; preds = %8, %4
381   %7 = phi i32 [ 0, %4 ], [ %14, %8 ]
382   ret i32 %7
384 ; <label>:8:                                      ; preds = %4, %8
385   %9 = phi i32 [ %15, %8 ], [ %0, %4 ]
386   %10 = phi i32 [ %14, %8 ], [ 0, %4 ]
387   %11 = zext i32 %9 to i64
388   %12 = getelementptr inbounds i32, i32* %2, i64 %11
389   %13 = load i32, i32* %12, align 4
390   %14 = add nsw i32 %13, %10
391   %15 = add i32 %9, %3
392   %16 = icmp eq i32 %15, %1
393   br i1 %16, label %6, label %8
397 ; TEST 13 (positive case)
398 ; Function Attrs: norecurse nounwind readonly uwtable
399 ;  int loop_trip_dec(int n, int *p){
400 ;    int ans = 0;
401 ;    for(;n >= 0;n--){
402 ;        ans += p[n];
403 ;    }
404 ;    return ans;
405 ;  }
408 ; FIXME: missing willreturn
409 ; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable
410 ; FNATTR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1)
411 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readonly uwtable
412 ; ATTRIBUTOR-NEXT: define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr
414 define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 {
415   %3 = icmp sgt i32 %0, -1
416   br i1 %3, label %4, label %14
418 ; <label>:4:                                      ; preds = %2
419   %5 = sext i32 %0 to i64
420   br label %6
422 ; <label>:6:                                      ; preds = %4, %6
423   %7 = phi i64 [ %5, %4 ], [ %12, %6 ]
424   %8 = phi i32 [ 0, %4 ], [ %11, %6 ]
425   %9 = getelementptr inbounds i32, i32* %1, i64 %7
426   %10 = load i32, i32* %9, align 4
427   %11 = add nsw i32 %10, %8
428   %12 = add nsw i64 %7, -1
429   %13 = icmp sgt i64 %7, 0
430   br i1 %13, label %6, label %14
432 ; <label>:14:                                     ; preds = %6, %2
433   %15 = phi i32 [ 0, %2 ], [ %11, %6 ]
434   ret i32 %15
437 ; TEST 14 (positive case)
438 ; multiple return
440 ; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable
441 ; FNATTR-NEXT: define i32 @multiple_return(i32 %a)
442 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn
443 ; ATTRIBUTOR-NEXT: define i32 @multiple_return(i32 %a)
444 define i32 @multiple_return(i32 %a) #0 {
445   %b =  icmp eq i32 %a, 0
446   br i1 %b, label %t, label %f
449   ret i32 1
451   ret i32 0
454 ; TEST 15 (positive & negative case)
455 ; unreachable exit
457 ; 15.1 (positive case)
458 ; FNATTR: Function Attrs: noinline nounwind uwtable
459 ; FNATTR-NEXT: define void @unreachable_exit_positive1()
460 ; ATTRIBUTOR: Function Attrs: noinline norecurse nounwind uwtable willreturn
461 ; ATTRIBUTOR-NEXT: define void @unreachable_exit_positive1()
462 define void @unreachable_exit_positive1() #0 {
463   tail call void @will_return()
464   ret void
466 unreachable_label:
467   tail call void @exit(i32 0)
468   unreachable
471 ; FIXME: missing willreturn
472 ; FNATTR: Function Attrs: noinline nounwind uwtable
473 ; FNATTR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
474 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable
475 ; ATTRIBUTOR-NEXT: define i32 @unreachable_exit_positive2(i32 %0)
476 define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 {
477   %2 = icmp slt i32 %0, 1
478   br i1 %2, label %3, label %5
480 ; <label>:3:                                      ; preds = %5, %1
481   %4 = phi i32 [ 1, %1 ], [ %8, %5 ]
482   ret i32 %4
484 ; <label>:5:                                      ; preds = %1, %5
485   %6 = phi i32 [ %9, %5 ], [ 1, %1 ]
486   %7 = phi i32 [ %8, %5 ], [ 1, %1 ]
487   %8 = mul nsw i32 %6, %7
488   %9 = add nuw nsw i32 %6, 1
489   %10 = icmp eq i32 %6, %0
490   br i1 %10, label %3, label %5
492 unreachable_label:
493   tail call void @exit(i32 0)
494   unreachable
498 ;15.2
500 ; FNATTR: Function Attrs: noinline nounwind uwtable
501 ; FNATTR-NOT: willreturn
502 ; FNATTR-NEXT: define void @unreachable_exit_negative1()
503 ; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
504 ; ATTRIBUTOR-NOT: willreturn
505 ; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative1()
506 define void @unreachable_exit_negative1() #0 {
507   tail call void @exit(i32 0)
508   ret void
510 unreachable_label:
511   tail call void @exit(i32 0)
512   unreachable
515 ; FNATTR: Function Attrs: noinline nounwind uwtable
516 ; FNATTR-NOT: willreturn
517 ; FNATTR-NEXT: define void @unreachable_exit_negative2()
518 ; ATTRIBUTOR: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable
519 ; ATTRIBUTOR-NOT: willreturn
520 ; ATTRIBUTOR-NEXT: define void @unreachable_exit_negative2()
521 define void @unreachable_exit_negative2() #0 {
523   br label %L1
525   br label %L2
527   br label %L1
529 unreachable_label:
530   tail call void @exit(i32 0)
531   unreachable
534 ; FNATTR: Function Attrs: noreturn nounwind
535 ; FNATTR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
536 ; ATTRIBUTOR: Function Attrs: noreturn nounwind
537 ; ATTRIBUTOR-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*)
538 declare void @llvm.eh.sjlj.longjmp(i8*)
540 ; FNATTR: Function Attrs: noinline nounwind uwtable
541 ; FNATTR-NOT: willreturn
542 ; FNATTR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #3 {
543 ; ATTRIBUTOR: Function Attrs: noinline noreturn nounwind uwtable
544 ; ATTRIBUTOR-NOT: willreturn
545 ; ATTRIBUTOR-NEXT: define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr
546 define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #0 {
547   tail call void @llvm.eh.sjlj.longjmp(i8* %0)
548   ret void
552 attributes #0 = { nounwind uwtable noinline }
553 attributes #1 = { uwtable noinline }