diff options
Diffstat (limited to 'llvm/test')
| -rw-r--r-- | llvm/test/Bitcode/attributes.ll | 11 | ||||
| -rw-r--r-- | llvm/test/Transforms/FunctionAttrs/willreturn.ll | 469 |
2 files changed, 478 insertions, 2 deletions
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll index 6f149c0d3bf..3aac9ee64ce 100644 --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -204,7 +204,7 @@ define void @f34() ; CHECK: define void @f34() { call void @nobuiltin() nobuiltin -; CHECK: call void @nobuiltin() #36 +; CHECK: call void @nobuiltin() #37 ret void; } @@ -351,6 +351,12 @@ define void @f59() shadowcallstack ret void } +; CHECK: define void @f60() #36 +define void @f60() willreturn +{ + ret void +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -387,4 +393,5 @@ define void @f59() shadowcallstack ; CHECK: attributes #33 = { speculatable } ; CHECK: attributes #34 = { sanitize_hwaddress } ; CHECK: attributes #35 = { shadowcallstack } -; CHECK: attributes #36 = { nobuiltin } +; CHECK: attributes #36 = { willreturn } +; CHECK: attributes #37 = { nobuiltin } diff --git a/llvm/test/Transforms/FunctionAttrs/willreturn.ll b/llvm/test/Transforms/FunctionAttrs/willreturn.ll new file mode 100644 index 00000000000..878538f9de3 --- /dev/null +++ b/llvm/test/Transforms/FunctionAttrs/willreturn.ll @@ -0,0 +1,469 @@ +; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +; Test cases specifically designed for the "willreturn" function attribute. +; We use FIXME's to indicate problems and missing attributes. + + +; TEST 1 (positive case) +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable +; FNATTR-NEXT: define void @only_return() +define void @only_return() #0 { + ret void +} + + +; TEST 2 (positive & negative case) +; 2.1 (positive case) +; recursive function which will halt +; int fib(int n){ +; return n<=1? n : fib(n-1) + fib(n-2); +; } + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline nounwind readnone uwtable +; FNATTR-NEXT: define i32 @fib(i32) +define i32 @fib(i32) local_unnamed_addr #0 { + %2 = icmp slt i32 %0, 2 + br i1 %2, label %9, label %3 + +; <label>:3: ; preds = %1 + %4 = add nsw i32 %0, -1 + %5 = tail call i32 @fib(i32 %4) + %6 = add nsw i32 %0, -2 + %7 = tail call i32 @fib(i32 %6) + %8 = add nsw i32 %7, %5 + ret i32 %8 + +; <label>:9: ; preds = %1 + ret i32 %0 +} + +; 2.2 (negative case) +; recursive function which doesn't stop for some input. +; int fact_maybe_not_halt(int n) { +; if (n==0) { +; return 1; +; } +; return fact_maybe_not_halt( n > 0 ? n-1 : n) * n; +; } +; fact_maybe_not(-1) doesn't stop. + +; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define i32 @fact_maybe_not_halt(i32) local_unnamed_addr +define i32 @fact_maybe_not_halt(i32) local_unnamed_addr #0 { + %2 = icmp eq i32 %0, 0 + br i1 %2, label %11, label %3 + +; <label>:3: ; preds = %1, %3 + %4 = phi i32 [ %8, %3 ], [ %0, %1 ] + %5 = phi i32 [ %9, %3 ], [ 1, %1 ] + %6 = icmp sgt i32 %4, 0 + %7 = sext i1 %6 to i32 + %8 = add nsw i32 %4, %7 + %9 = mul nsw i32 %4, %5 + %10 = icmp eq i32 %8, 0 + br i1 %10, label %11, label %3 + +; <label>:11: ; preds = %3, %1 + %12 = phi i32 [ 1, %1 ], [ %9, %3 ] + ret i32 %12 +} + + +; TEST 3 (positive case) +; loop +; int fact_loop(int n ){ +; int ans = 1; +; for(int i = 1;i<=n;i++){ +; ans *= i; +; } +; return ans; +; } + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable +; FNATTR-NEXT: define i32 @fact_loop(i32) +define i32 @fact_loop(i32) local_unnamed_addr #0 { + %2 = icmp slt i32 %0, 1 + br i1 %2, label %3, label %5 + +; <label>:3: ; preds = %5, %1 + %4 = phi i32 [ 1, %1 ], [ %8, %5 ] + ret i32 %4 + +; <label>:5: ; preds = %1, %5 + %6 = phi i32 [ %9, %5 ], [ 1, %1 ] + %7 = phi i32 [ %8, %5 ], [ 1, %1 ] + %8 = mul nsw i32 %6, %7 + %9 = add nuw nsw i32 %6, 1 + %10 = icmp eq i32 %6, %0 + br i1 %10, label %3, label %5 +} + +; TEST 4 (negative case) +; mutual recursion +; void mutual_recursion1(){ +; mutual_recursion2(); +; } +; void mutual_recursion2(){ +; mutual_recursion1(); +; } + +; FNATTR: Function Attrs: noinline nounwind readnone uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @mutual_recursion1() +define void @mutual_recursion1() #0 { + call void @mutual_recursion2() + ret void +} + + +; FNATTR: Function Attrs: noinline nounwind readnone uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @mutual_recursion2() +define void @mutual_recursion2() #0 { + call void @mutual_recursion1() + ret void +} + + +; TEST 5 (negative case) +; call exit/abort (has noreturn attribute) +; FNATTR: Function Attrs: noreturn +; FNATTR-NEXT: declare void @exit(i32) local_unnamed_addr +declare void @exit(i32) local_unnamed_addr noreturn + +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @only_exit() +define void @only_exit() local_unnamed_addr #0 { + tail call void @exit(i32 0) + unreachable +} + +; conditional exit +; void conditional_exit(int cond, int *p){ +; if(cond){ +; exit(0); +; } +; if(*p){ +; exit(1); +; } +; return; +; } +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @conditional_exit(i32, i32* nocapture readonly) local_unnamed_addr +define void @conditional_exit(i32, i32* nocapture readonly) local_unnamed_addr #0 { + %3 = icmp eq i32 %0, 0 + br i1 %3, label %5, label %4 + +; <label>:4: ; preds = %2 + tail call void @exit(i32 0) + unreachable + +; <label>:5: ; preds = %2 + %6 = load i32, i32* %1, align 4 + %7 = icmp eq i32 %6, 0 + br i1 %7, label %9, label %8 + +; <label>:8: ; preds = %5 + tail call void @exit(i32 1) + unreachable + +; <label>:9: ; preds = %5 + ret void +} + +; TEST 6 (positive case) +; Call intrinsic function +; FNATTRS: Function Attrs: noinline readnone speculatable +; FNATTRS-NEXT: declare float @llvm.floor.f32(float) +declare float @llvm.floor.f32(float) + +; FIXME: missing willreturn +; FNATTRS: Function Attrs: noinline nounwind uwtable +; FNATTRS-NEXT: define void @call_floor(float %a) +define void @call_floor(float %a) #0 { + tail call float @llvm.floor.f32(float %a) + ret void +} + + +; TEST 7 (negative case) +; Call function declaration without willreturn + +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: declare void @maybe_noreturn() +declare void @maybe_noreturn() #0 + +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @call_maybe_noreturn() +define void @call_maybe_noreturn() #0 { + tail call void @maybe_noreturn() + ret void +} + + +; TEST 8 (positive case) +; Check propagation. + +; FNATTR: Function Attrs: willreturn +; FNATTR-NEXT: declare void @will_return() +declare void @will_return() willreturn + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NEXT: define void @f1() +define void @f1() #0 { + tail call void @will_return() + ret void +} + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NEXT: define void @f2() +define void @f2() #0 { + tail call void @f1() + ret void +} + + +; TEST 9 (negative case) +; call willreturn function in endless loop. + +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @call_will_return_but_has_loop() +define void @call_will_return_but_has_loop() #0 { + br label %label1 +label1: + tail call void @will_return() + br label %label2 +label2: + br label %label1 +} + + +; TEST 10 (positive case) +; invoke a function with willreturn + +; FNATTR: Function Attrs: noinline uwtable willreturn +; FNATTR-NEXT: declare i1 @maybe_raise_exception() +declare i1 @maybe_raise_exception() #1 willreturn + +; FIXME: missing willreturn +; FNATTR: Function Attrs: nounwind +; FNATTR-NEXT: define void @invoke_test() +define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 { + invoke i1 @maybe_raise_exception() + to label %N unwind label %F + N: + ret void + F: + %val = landingpad { i8*, i32 } + catch i8* null + ret void +} + +declare i32 @__gxx_personality_v0(...) + + +; TEST 11 (positive case) +; counstant trip count +; int loop_constant_trip_count(int*p){ +; int ans = 0; +; for(int i = 0;i<10;i++){ +; ans += p[i]; +; } +; return ans; +; } + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable +; FNATTR-NEXT: define i32 @loop_constant_trip_count(i32* nocapture readonly) +define i32 @loop_constant_trip_count(i32* nocapture readonly) #0 { + br label %3 + +; <label>:2: ; preds = %3 + ret i32 %8 + +; <label>:3: ; preds = %3, %1 + %4 = phi i64 [ 0, %1 ], [ %9, %3 ] + %5 = phi i32 [ 0, %1 ], [ %8, %3 ] + %6 = getelementptr inbounds i32, i32* %0, i64 %4 + %7 = load i32, i32* %6, align 4 + %8 = add nsw i32 %7, %5 + %9 = add nuw nsw i64 %4, 1 + %10 = icmp eq i64 %9, 10 + br i1 %10, label %2, label %3 +} + + +; TEST 12 (negative case) +; unbounded trip count + +; int loop_trip_count_unbound(unsigned s,unsigned e, int *p, int offset){ +; int ans = 0; +; for(unsigned i = s;i != e;i+=offset){ +; ans += p[i]; +; } +; return ans; +; } +; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define i32 @loop_trip_count_unbound(i32, i32, i32* nocapture readonly, i32) local_unnamed_addr +define i32 @loop_trip_count_unbound(i32, i32, i32* nocapture readonly, i32) local_unnamed_addr #0 { + %5 = icmp eq i32 %0, %1 + br i1 %5, label %6, label %8 + +; <label>:6: ; preds = %8, %4 + %7 = phi i32 [ 0, %4 ], [ %14, %8 ] + ret i32 %7 + +; <label>:8: ; preds = %4, %8 + %9 = phi i32 [ %15, %8 ], [ %0, %4 ] + %10 = phi i32 [ %14, %8 ], [ 0, %4 ] + %11 = zext i32 %9 to i64 + %12 = getelementptr inbounds i32, i32* %2, i64 %11 + %13 = load i32, i32* %12, align 4 + %14 = add nsw i32 %13, %10 + %15 = add i32 %9, %3 + %16 = icmp eq i32 %15, %1 + br i1 %16, label %6, label %8 +} + + +; TEST 13 (positive case) +; Function Attrs: norecurse nounwind readonly uwtable +; int loop_trip_dec(int n, int *p){ +; int ans = 0; +; for(;n >= 0;n--){ +; ans += p[n]; +; } +; return ans; +; } + + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline norecurse nounwind readonly uwtable +; FNATTR-NEXT: define i32 @loop_trip_dec(i32, i32* nocapture readonly) + +define i32 @loop_trip_dec(i32, i32* nocapture readonly) local_unnamed_addr #0 { + %3 = icmp sgt i32 %0, -1 + br i1 %3, label %4, label %14 + +; <label>:4: ; preds = %2 + %5 = sext i32 %0 to i64 + br label %6 + +; <label>:6: ; preds = %4, %6 + %7 = phi i64 [ %5, %4 ], [ %12, %6 ] + %8 = phi i32 [ 0, %4 ], [ %11, %6 ] + %9 = getelementptr inbounds i32, i32* %1, i64 %7 + %10 = load i32, i32* %9, align 4 + %11 = add nsw i32 %10, %8 + %12 = add nsw i64 %7, -1 + %13 = icmp sgt i64 %7, 0 + br i1 %13, label %6, label %14 + +; <label>:14: ; preds = %6, %2 + %15 = phi i32 [ 0, %2 ], [ %11, %6 ] + ret i32 %15 +} + +; TEST 14 (positive case) +; multiple return + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline norecurse nounwind readnone uwtable +; FNATTR-NEXT: define i32 @multiple_return(i32 %a) +define i32 @multiple_return(i32 %a) #0 { + %b = icmp eq i32 %a, 0 + br i1 %b, label %t, label %f + +t: + ret i32 1 +f: + ret i32 0 +} + +; TEST 15 (positive & negative case) +; unreachable exit + +; 15.1 (positive case) +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NEXT: define void @unreachable_exit_positive1() +define void @unreachable_exit_positive1() #0 { + tail call void @will_return() + ret void + +unreachable_label: + tail call void @exit(i32 0) + unreachable +} + +; FIXME: missing willreturn +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NEXT: define i32 @unreachable_exit_positive2(i32) +define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 { + %2 = icmp slt i32 %0, 1 + br i1 %2, label %3, label %5 + +; <label>:3: ; preds = %5, %1 + %4 = phi i32 [ 1, %1 ], [ %8, %5 ] + ret i32 %4 + +; <label>:5: ; preds = %1, %5 + %6 = phi i32 [ %9, %5 ], [ 1, %1 ] + %7 = phi i32 [ %8, %5 ], [ 1, %1 ] + %8 = mul nsw i32 %6, %7 + %9 = add nuw nsw i32 %6, 1 + %10 = icmp eq i32 %6, %0 + br i1 %10, label %3, label %5 + +unreachable_label: + tail call void @exit(i32 0) + unreachable +} + +;15.2 + +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @unreachable_exit_negative1() +define void @unreachable_exit_negative1() #0 { + tail call void @exit(i32 0) + ret void + +unreachable_label: + tail call void @exit(i32 0) + unreachable +} + +; FNATTR: Function Attrs: noinline nounwind uwtable +; FNATTR-NOT: willreturn +; FNATTR-NEXT: define void @unreachable_exit_negative2() +define void @unreachable_exit_negative2() #0 { + + br label %L1 +L1: + br label %L2 +L2: + br label %L1 + +unreachable_label: + tail call void @exit(i32 0) + unreachable +} + + +attributes #0 = { nounwind uwtable noinline } +attributes #1 = { uwtable noinline } |

