| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes |
| ; RUN: opt -attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=8 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=8 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM |
| ; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM |
| |
| target datalayout = "e-m:e-i54: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) |
| ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn |
| ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn |
| define void @only_return() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@only_return() |
| ; CHECK-NEXT: ret void |
| ; |
| 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 |
| ; CHECK: Function Attrs: nofree noinline nosync nounwind readnone uwtable |
| define i32 @fib(i32 %0) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@fib |
| ; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 2 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[TMP9:%.*]], label [[TMP3:%.*]] |
| ; CHECK: 3: |
| ; CHECK-NEXT: [[TMP4:%.*]] = add nsw i32 [[TMP0]], -1 |
| ; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @fib(i32 [[TMP4]]) |
| ; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP0]], -2 |
| ; CHECK-NEXT: [[TMP7:%.*]] = tail call i32 @fib(i32 [[TMP6]]) |
| ; CHECK-NEXT: [[TMP8:%.*]] = add nsw i32 [[TMP7]], [[TMP5]] |
| ; CHECK-NEXT: ret i32 [[TMP8]] |
| ; CHECK: 9: |
| ; CHECK-NEXT: ret i32 [[TMP0]] |
| ; |
| %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. |
| |
| ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable |
| ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable |
| ; CHECK-NOT: willreturn |
| define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@fact_maybe_not_halt |
| ; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP0]], 0 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[TMP11:%.*]], label [[TMP3:%.*]] |
| ; CHECK: 3: |
| ; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ [[TMP8:%.*]], [[TMP3]] ], [ [[TMP0]], [[TMP1:%.*]] ] |
| ; CHECK-NEXT: [[TMP5:%.*]] = phi i32 [ [[TMP9:%.*]], [[TMP3]] ], [ 1, [[TMP1]] ] |
| ; CHECK-NEXT: [[TMP6:%.*]] = icmp sgt i32 [[TMP4]], 0 |
| ; CHECK-NEXT: [[TMP7:%.*]] = sext i1 [[TMP6]] to i32 |
| ; CHECK-NEXT: [[TMP8]] = add nsw i32 [[TMP4]], [[TMP7]] |
| ; CHECK-NEXT: [[TMP9]] = mul nsw i32 [[TMP4]], [[TMP5]] |
| ; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP8]], 0 |
| ; CHECK-NEXT: br i1 [[TMP10]], label [[TMP11]], label [[TMP3]] |
| ; CHECK: 11: |
| ; CHECK-NEXT: [[TMP12:%.*]] = phi i32 [ 1, [[TMP1]] ], [ [[TMP9]], [[TMP3]] ] |
| ; CHECK-NEXT: ret i32 [[TMP12]] |
| ; |
| %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; |
| ; } |
| |
| ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable |
| ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable |
| define i32 @fact_loop(i32 %0) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@fact_loop |
| ; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 1 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] |
| ; CHECK: 3: |
| ; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ 1, [[TMP1:%.*]] ], [ [[TMP8:%.*]], [[TMP5]] ] |
| ; CHECK-NEXT: ret i32 [[TMP4]] |
| ; CHECK: 5: |
| ; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP9:%.*]], [[TMP5]] ], [ 1, [[TMP1]] ] |
| ; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8]], [[TMP5]] ], [ 1, [[TMP1]] ] |
| ; CHECK-NEXT: [[TMP8]] = mul nsw i32 [[TMP6]], [[TMP7]] |
| ; CHECK-NEXT: [[TMP9]] = add nuw nsw i32 [[TMP6]], 1 |
| ; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP6]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[TMP10]], label [[TMP3]], label [[TMP5]] |
| ; |
| %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(); |
| ; } |
| |
| declare void @sink() nounwind willreturn nosync nofree |
| |
| ; CHECK: Function Attrs: nofree noinline nosync nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @mutual_recursion1(i1 %c) #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@mutual_recursion1 |
| ; CHECK-SAME: (i1 [[C:%.*]]) |
| ; CHECK-NEXT: br i1 [[C]], label [[REC:%.*]], label [[END:%.*]] |
| ; CHECK: rec: |
| ; CHECK-NEXT: call void @sink() |
| ; CHECK-NEXT: call void @mutual_recursion2(i1 [[C]]) |
| ; CHECK-NEXT: br label [[END]] |
| ; CHECK: end: |
| ; CHECK-NEXT: ret void |
| ; |
| br i1 %c, label %rec, label %end |
| rec: |
| call void @sink() |
| call void @mutual_recursion2(i1 %c) |
| br label %end |
| end: |
| ret void |
| } |
| |
| |
| ; CHECK: Function Attrs: nofree noinline nosync nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @mutual_recursion2(i1 %c) #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@mutual_recursion2 |
| ; CHECK-SAME: (i1 [[C:%.*]]) |
| ; CHECK-NEXT: call void @mutual_recursion1(i1 [[C]]) |
| ; CHECK-NEXT: ret void |
| ; |
| call void @mutual_recursion1(i1 %c) |
| ret void |
| } |
| |
| |
| ; TEST 5 (negative case) |
| ; call exit/abort (has noreturn attribute) |
| ; CHECK: Function Attrs: noreturn |
| ; CHECK-NEXT: declare void @exit(i32) local_unnamed_add |
| declare void @exit(i32 %0) local_unnamed_addr noreturn |
| |
| ; CHECK: Function Attrs: noinline noreturn nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @only_exit() local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@only_exit() local_unnamed_addr |
| ; CHECK-NEXT: tail call void @exit(i32 0) |
| ; CHECK-NEXT: unreachable |
| ; |
| 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; |
| ; } |
| ; CHECK: Function Attrs: noinline nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @conditional_exit(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@conditional_exit |
| ; CHECK-SAME: (i32 [[TMP0:%.*]], i32* nocapture readonly [[TMP1:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP0]], 0 |
| ; CHECK-NEXT: br i1 [[TMP3]], label [[TMP5:%.*]], label [[TMP4:%.*]] |
| ; CHECK: 4: |
| ; CHECK-NEXT: tail call void @exit(i32 0) |
| ; CHECK-NEXT: unreachable |
| ; CHECK: 5: |
| ; CHECK-NEXT: [[TMP6:%.*]] = load i32, i32* [[TMP1]], align 4 |
| ; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i32 [[TMP6]], 0 |
| ; CHECK-NEXT: br i1 [[TMP7]], label [[TMP9:%.*]], label [[TMP8:%.*]] |
| ; CHECK: 8: |
| ; CHECK-NEXT: tail call void @exit(i32 1) |
| ; CHECK-NEXT: unreachable |
| ; CHECK: 9: |
| ; CHECK-NEXT: ret void |
| ; |
| %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 |
| ; CHECK: Function Attrs: nounwind readnone speculatable willreturn |
| ; CHECK-NEXT: declare float @llvm.floor.f32(float) |
| declare float @llvm.floor.f32(float) |
| |
| ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn |
| ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn |
| define void @call_floor(float %a) #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@call_floor |
| ; CHECK-SAME: (float [[A:%.*]]) |
| ; CHECK-NEXT: ret void |
| ; |
| tail call float @llvm.floor.f32(float %a) |
| ret void |
| } |
| |
| ; CHECK: Function Attrs: noinline nosync nounwind readnone uwtable willreturn |
| define float @call_floor2(float %a) #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@call_floor2 |
| ; CHECK-SAME: (float [[A:%.*]]) |
| ; CHECK-NEXT: [[C:%.*]] = tail call float @llvm.floor.f32(float [[A]]) |
| ; CHECK-NEXT: ret float [[C]] |
| ; |
| %c = tail call float @llvm.floor.f32(float %a) |
| ret float %c |
| } |
| |
| |
| ; TEST 7 (negative case) |
| ; Call function declaration without willreturn |
| |
| ; CHECK: Function Attrs: noinline nounwind uwtable |
| ; CHECK-NOT: willreturn |
| ; CHECK-NEXT: declare void @maybe_noreturn() |
| declare void @maybe_noreturn() #0 |
| |
| ; CHECK: Function Attrs: noinline nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @call_maybe_noreturn() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@call_maybe_noreturn() |
| ; CHECK-NEXT: tail call void @maybe_noreturn() |
| ; CHECK-NEXT: ret void |
| ; |
| tail call void @maybe_noreturn() |
| ret void |
| } |
| |
| |
| ; TEST 8 (positive case) |
| ; Check propagation. |
| |
| ; CHECK: Function Attrs: norecurse willreturn |
| ; CHECK-NEXT: declare void @will_return() |
| declare void @will_return() willreturn norecurse |
| |
| ; IS__TUNIT____: Function Attrs: noinline nounwind uwtable willreturn |
| ; IS__CGSCC____: Function Attrs: noinline norecurse nounwind uwtable willreturn |
| define void @f1() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@f1() |
| ; CHECK-NEXT: tail call void @will_return() |
| ; CHECK-NEXT: ret void |
| ; |
| tail call void @will_return() |
| ret void |
| } |
| |
| ; IS__TUNIT____: Function Attrs: noinline nounwind uwtable willreturn |
| ; IS__CGSCC____: Function Attrs: noinline norecurse nounwind uwtable willreturn |
| define void @f2() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@f2() |
| ; CHECK-NEXT: tail call void @f1() |
| ; CHECK-NEXT: ret void |
| ; |
| tail call void @f1() |
| ret void |
| } |
| |
| |
| ; TEST 9 (negative case) |
| ; call willreturn function in endless loop. |
| |
| ; IS__TUNIT____: Function Attrs: noinline noreturn nounwind uwtable |
| ; IS__CGSCC____: Function Attrs: noinline norecurse noreturn nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @call_will_return_but_has_loop() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@call_will_return_but_has_loop() |
| ; CHECK-NEXT: br label [[LABEL1:%.*]] |
| ; CHECK: label1: |
| ; CHECK-NEXT: tail call void @will_return() |
| ; CHECK-NEXT: br label [[LABEL2:%.*]] |
| ; CHECK: label2: |
| ; CHECK-NEXT: br label [[LABEL1]] |
| ; |
| 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 |
| |
| ; CHECK: Function Attrs: noinline uwtable willreturn |
| ; CHECK-NEXT: declare i1 @maybe_raise_exception() |
| declare i1 @maybe_raise_exception() #1 willreturn |
| |
| ; CHECK: Function Attrs: nounwind willreturn |
| define void @invoke_test() personality i32 (...)* @__gxx_personality_v0 { |
| ; IS__TUNIT____-LABEL: define {{[^@]+}}@invoke_test() #12 personality i32 (...)* @__gxx_personality_v0 |
| ; IS__TUNIT____-NEXT: [[TMP1:%.*]] = invoke i1 @maybe_raise_exception() |
| ; IS__TUNIT____-NEXT: to label [[N:%.*]] unwind label [[F:%.*]] |
| ; IS__TUNIT____: N: |
| ; IS__TUNIT____-NEXT: ret void |
| ; IS__TUNIT____: F: |
| ; IS__TUNIT____-NEXT: [[VAL:%.*]] = landingpad { i8*, i32 } |
| ; IS__TUNIT____-NEXT: catch i8* null |
| ; IS__TUNIT____-NEXT: ret void |
| ; |
| ; IS__CGSCC____-LABEL: define {{[^@]+}}@invoke_test() #14 personality i32 (...)* @__gxx_personality_v0 |
| ; IS__CGSCC____-NEXT: [[TMP1:%.*]] = invoke i1 @maybe_raise_exception() |
| ; IS__CGSCC____-NEXT: to label [[N:%.*]] unwind label [[F:%.*]] |
| ; IS__CGSCC____: N: |
| ; IS__CGSCC____-NEXT: ret void |
| ; IS__CGSCC____: F: |
| ; IS__CGSCC____-NEXT: [[VAL:%.*]] = landingpad { i8*, i32 } |
| ; IS__CGSCC____-NEXT: catch i8* null |
| ; IS__CGSCC____-NEXT: ret void |
| ; |
| 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) |
| ; constant trip count |
| ; int loop_constant_trip_count(int*p){ |
| ; int ans = 0; |
| ; for(int i = 0;i<10;i++){ |
| ; ans += p[i]; |
| ; } |
| ; return ans; |
| ; } |
| |
| ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable |
| ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable |
| define i32 @loop_constant_trip_count(i32* nocapture readonly %0) #0 { |
| ; IS________OPM-LABEL: define {{[^@]+}}@loop_constant_trip_count |
| ; IS________OPM-SAME: (i32* nocapture nofree readonly [[TMP0:%.*]]) |
| ; IS________OPM-NEXT: br label [[TMP3:%.*]] |
| ; IS________OPM: 2: |
| ; IS________OPM-NEXT: ret i32 [[TMP8:%.*]] |
| ; IS________OPM: 3: |
| ; IS________OPM-NEXT: [[TMP4:%.*]] = phi i64 [ 0, [[TMP1:%.*]] ], [ [[TMP9:%.*]], [[TMP3]] ] |
| ; IS________OPM-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP1]] ], [ [[TMP8]], [[TMP3]] ] |
| ; IS________OPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP4]] |
| ; IS________OPM-NEXT: [[TMP7:%.*]] = load i32, i32* [[TMP6]], align 4 |
| ; IS________OPM-NEXT: [[TMP8]] = add nsw i32 [[TMP7]], [[TMP5]] |
| ; IS________OPM-NEXT: [[TMP9]] = add nuw nsw i64 [[TMP4]], 1 |
| ; IS________OPM-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 10 |
| ; IS________OPM-NEXT: br i1 [[TMP10]], label [[TMP2:%.*]], label [[TMP3]] |
| ; |
| ; IS________NPM-LABEL: define {{[^@]+}}@loop_constant_trip_count |
| ; IS________NPM-SAME: (i32* nocapture nofree nonnull readonly dereferenceable(4) [[TMP0:%.*]]) |
| ; IS________NPM-NEXT: br label [[TMP3:%.*]] |
| ; IS________NPM: 2: |
| ; IS________NPM-NEXT: ret i32 [[TMP8:%.*]] |
| ; IS________NPM: 3: |
| ; IS________NPM-NEXT: [[TMP4:%.*]] = phi i64 [ 0, [[TMP1:%.*]] ], [ [[TMP9:%.*]], [[TMP3]] ] |
| ; IS________NPM-NEXT: [[TMP5:%.*]] = phi i32 [ 0, [[TMP1]] ], [ [[TMP8]], [[TMP3]] ] |
| ; IS________NPM-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 [[TMP4]] |
| ; IS________NPM-NEXT: [[TMP7:%.*]] = load i32, i32* [[TMP6]], align 4 |
| ; IS________NPM-NEXT: [[TMP8]] = add nsw i32 [[TMP7]], [[TMP5]] |
| ; IS________NPM-NEXT: [[TMP9]] = add nuw nsw i64 [[TMP4]], 1 |
| ; IS________NPM-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 10 |
| ; IS________NPM-NEXT: br i1 [[TMP10]], label [[TMP2:%.*]], label [[TMP3]] |
| ; |
| 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; |
| ; } |
| ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable |
| ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable |
| ; CHECK-NOT: willreturn |
| define i32 @loop_trip_count_unbound(i32 %0, i32 %1, i32* nocapture readonly %2, i32 %3) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@loop_trip_count_unbound |
| ; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32* nocapture nofree readonly [[TMP2:%.*]], i32 [[TMP3:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]] |
| ; CHECK-NEXT: br i1 [[TMP5]], label [[TMP6:%.*]], label [[TMP8:%.*]] |
| ; CHECK: 6: |
| ; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ 0, [[TMP4:%.*]] ], [ [[TMP14:%.*]], [[TMP8]] ] |
| ; CHECK-NEXT: ret i32 [[TMP7]] |
| ; CHECK: 8: |
| ; CHECK-NEXT: [[TMP9:%.*]] = phi i32 [ [[TMP15:%.*]], [[TMP8]] ], [ [[TMP0]], [[TMP4]] ] |
| ; CHECK-NEXT: [[TMP10:%.*]] = phi i32 [ [[TMP14]], [[TMP8]] ], [ 0, [[TMP4]] ] |
| ; CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[TMP9]] to i64 |
| ; CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds i32, i32* [[TMP2]], i64 [[TMP11]] |
| ; CHECK-NEXT: [[TMP13:%.*]] = load i32, i32* [[TMP12]], align 4 |
| ; CHECK-NEXT: [[TMP14]] = add nsw i32 [[TMP13]], [[TMP10]] |
| ; CHECK-NEXT: [[TMP15]] = add i32 [[TMP9]], [[TMP3]] |
| ; CHECK-NEXT: [[TMP16:%.*]] = icmp eq i32 [[TMP15]], [[TMP1]] |
| ; CHECK-NEXT: br i1 [[TMP16]], label [[TMP6]], label [[TMP8]] |
| ; |
| %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; |
| ; } |
| |
| |
| ; IS__TUNIT____: Function Attrs: argmemonly nofree noinline nosync nounwind readonly uwtable |
| ; IS__CGSCC____: Function Attrs: argmemonly nofree noinline norecurse nosync nounwind readonly uwtable |
| define i32 @loop_trip_dec(i32 %0, i32* nocapture readonly %1) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@loop_trip_dec |
| ; CHECK-SAME: (i32 [[TMP0:%.*]], i32* nocapture nofree readonly [[TMP1:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: [[TMP3:%.*]] = icmp sgt i32 [[TMP0]], -1 |
| ; CHECK-NEXT: br i1 [[TMP3]], label [[TMP4:%.*]], label [[TMP14:%.*]] |
| ; CHECK: 4: |
| ; CHECK-NEXT: [[TMP5:%.*]] = sext i32 [[TMP0]] to i64 |
| ; CHECK-NEXT: br label [[TMP6:%.*]] |
| ; CHECK: 6: |
| ; CHECK-NEXT: [[TMP7:%.*]] = phi i64 [ [[TMP5]], [[TMP4]] ], [ [[TMP12:%.*]], [[TMP6]] ] |
| ; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ 0, [[TMP4]] ], [ [[TMP11:%.*]], [[TMP6]] ] |
| ; CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds i32, i32* [[TMP1]], i64 [[TMP7]] |
| ; CHECK-NEXT: [[TMP10:%.*]] = load i32, i32* [[TMP9]], align 4 |
| ; CHECK-NEXT: [[TMP11]] = add nsw i32 [[TMP10]], [[TMP8]] |
| ; CHECK-NEXT: [[TMP12]] = add nsw i64 [[TMP7]], -1 |
| ; CHECK-NEXT: [[TMP13:%.*]] = icmp sgt i64 [[TMP7]], 0 |
| ; CHECK-NEXT: br i1 [[TMP13]], label [[TMP6]], label [[TMP14]] |
| ; CHECK: 14: |
| ; CHECK-NEXT: [[TMP15:%.*]] = phi i32 [ 0, [[TMP2:%.*]] ], [ [[TMP11]], [[TMP6]] ] |
| ; CHECK-NEXT: ret i32 [[TMP15]] |
| ; |
| %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 |
| |
| ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable willreturn |
| ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable willreturn |
| define i32 @multiple_return(i32 %a) #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@multiple_return |
| ; CHECK-SAME: (i32 [[A:%.*]]) |
| ; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[A]], 0 |
| ; CHECK-NEXT: br i1 [[B]], label [[T:%.*]], label [[F:%.*]] |
| ; CHECK: t: |
| ; CHECK-NEXT: ret i32 1 |
| ; CHECK: f: |
| ; CHECK-NEXT: ret i32 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) |
| ; IS__TUNIT____: Function Attrs: noinline nounwind uwtable |
| ; IS__CGSCC____: Function Attrs: noinline norecurse nounwind uwtable willreturn |
| define void @unreachable_exit_positive1() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_positive1() |
| ; CHECK-NEXT: tail call void @will_return() |
| ; CHECK-NEXT: ret void |
| ; CHECK: unreachable_label: |
| ; CHECK-NEXT: unreachable |
| ; |
| tail call void @will_return() |
| ret void |
| |
| unreachable_label: |
| tail call void @exit(i32 0) |
| unreachable |
| } |
| |
| ; IS__TUNIT____: Function Attrs: nofree noinline nosync nounwind readnone uwtable |
| ; IS__CGSCC____: Function Attrs: nofree noinline norecurse nosync nounwind readnone uwtable |
| define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_positive2 |
| ; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 1 |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] |
| ; CHECK: 3: |
| ; CHECK-NEXT: [[TMP4:%.*]] = phi i32 [ 1, [[TMP1:%.*]] ], [ [[TMP8:%.*]], [[TMP5]] ] |
| ; CHECK-NEXT: ret i32 [[TMP4]] |
| ; CHECK: 5: |
| ; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP9:%.*]], [[TMP5]] ], [ 1, [[TMP1]] ] |
| ; CHECK-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP8]], [[TMP5]] ], [ 1, [[TMP1]] ] |
| ; CHECK-NEXT: [[TMP8]] = mul nsw i32 [[TMP6]], [[TMP7]] |
| ; CHECK-NEXT: [[TMP9]] = add nuw nsw i32 [[TMP6]], 1 |
| ; CHECK-NEXT: [[TMP10:%.*]] = icmp eq i32 [[TMP6]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[TMP10]], label [[TMP3]], label [[TMP5]] |
| ; CHECK: unreachable_label: |
| ; CHECK-NEXT: unreachable |
| ; |
| %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 |
| |
| ; CHECK: Function Attrs: noinline noreturn nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @unreachable_exit_negative1() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_negative1() |
| ; CHECK-NEXT: tail call void @exit(i32 0) |
| ; CHECK-NEXT: unreachable |
| ; CHECK: unreachable_label: |
| ; CHECK-NEXT: unreachable |
| ; |
| tail call void @exit(i32 0) |
| ret void |
| |
| unreachable_label: |
| tail call void @exit(i32 0) |
| unreachable |
| } |
| |
| ; IS__TUNIT____: Function Attrs: nofree noinline noreturn nosync nounwind readnone uwtable |
| ; IS__CGSCC____: Function Attrs: nofree noinline norecurse noreturn nosync nounwind readnone uwtable |
| ; CHECK-NOT: willreturn |
| define void @unreachable_exit_negative2() #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_negative2() |
| ; CHECK-NEXT: br label [[L1:%.*]] |
| ; CHECK: L1: |
| ; CHECK-NEXT: br label [[L2:%.*]] |
| ; CHECK: L2: |
| ; CHECK-NEXT: br label [[L1]] |
| ; CHECK: unreachable_label: |
| ; CHECK-NEXT: unreachable |
| ; |
| br label %L1 |
| L1: |
| br label %L2 |
| L2: |
| br label %L1 |
| |
| unreachable_label: |
| tail call void @exit(i32 0) |
| unreachable |
| } |
| |
| ; CHECK: Function Attrs: noreturn nounwind |
| ; CHECK-NEXT: declare void @llvm.eh.sjlj.longjmp(i8*) |
| declare void @llvm.eh.sjlj.longjmp(i8*) |
| |
| ; CHECK: Function Attrs: noinline noreturn nounwind uwtable |
| ; CHECK-NOT: willreturn |
| define void @call_longjmp(i8* nocapture readnone %0) local_unnamed_addr #0 { |
| ; CHECK-LABEL: define {{[^@]+}}@call_longjmp |
| ; CHECK-SAME: (i8* nocapture readnone [[TMP0:%.*]]) local_unnamed_addr |
| ; CHECK-NEXT: tail call void @llvm.eh.sjlj.longjmp(i8* noalias readnone [[TMP0]]) |
| ; CHECK-NEXT: unreachable |
| ; |
| tail call void @llvm.eh.sjlj.longjmp(i8* %0) |
| ret void |
| } |
| |
| |
| ; TEST 16 (negative case) |
| ; int infinite_loop_inside_bounded_loop(int n) { |
| ; int ans = 0; |
| ; for (int i = 0; i < n; i++) { |
| ; while (1) |
| ; ans++; |
| ; } |
| ; return ans; |
| ; } |
| |
| ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone |
| ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone |
| ; CHECK-NOT: willreturn |
| define i32 @infinite_loop_inside_bounded_loop(i32 %n) { |
| ; CHECK-LABEL: define {{[^@]+}}@infinite_loop_inside_bounded_loop |
| ; CHECK-SAME: (i32 [[N:%.*]]) |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_COND:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N]], 0 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]] |
| ; CHECK: for.cond.cleanup: |
| ; CHECK-NEXT: br label [[FOR_END:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: br label [[WHILE_COND:%.*]] |
| ; CHECK: while.cond: |
| ; CHECK-NEXT: br label [[WHILE_BODY:%.*]] |
| ; CHECK: while.body: |
| ; CHECK-NEXT: br label [[WHILE_COND]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: for.end: |
| ; CHECK-NEXT: ret i32 0 |
| ; |
| entry: |
| br label %for.cond |
| |
| for.cond: ; preds = %for.inc, %entry |
| %cmp = icmp sgt i32 %n, 0 |
| br i1 %cmp, label %for.body, label %for.cond.cleanup |
| |
| for.cond.cleanup: ; preds = %for.cond |
| br label %for.end |
| |
| for.body: ; preds = %for.cond |
| br label %while.cond |
| |
| while.cond: ; preds = %while.body, %for.body |
| br label %while.body |
| |
| while.body: ; preds = %while.cond |
| br label %while.cond |
| |
| for.inc: ; No predecessors! |
| br label %for.cond |
| |
| for.end: ; preds = %for.cond.cleanup |
| ret i32 0 |
| } |
| |
| |
| ; TEST 17 (positive case) |
| ; Nested loops with constant max trip count |
| ; int bounded_nested_loops(int n) { |
| ; int ans = 0; |
| ; for (int i = 0; i < n; i++) { |
| ; while (n--) { |
| ; ans++; |
| ; } |
| ; } |
| ; return ans; |
| ; } |
| |
| ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone |
| ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone |
| define i32 @bounded_nested_loops(i32 %n) { |
| ; CHECK-LABEL: define {{[^@]+}}@bounded_nested_loops |
| ; CHECK-SAME: (i32 [[N:%.*]]) |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_COND:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC1:%.*]], [[FOR_INC:%.*]] ] |
| ; CHECK-NEXT: [[ANS_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[TMP:%.*]], [[FOR_INC]] ] |
| ; CHECK-NEXT: [[N_ADDR_0:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ -1, [[FOR_INC]] ] |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], [[N_ADDR_0]] |
| ; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_COND_CLEANUP:%.*]] |
| ; CHECK: for.cond.cleanup: |
| ; CHECK-NEXT: [[ANS_0_LCSSA:%.*]] = phi i32 [ [[ANS_0]], [[FOR_COND]] ] |
| ; CHECK-NEXT: br label [[FOR_END:%.*]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: br label [[WHILE_COND:%.*]] |
| ; CHECK: while.cond: |
| ; CHECK-NEXT: br i1 true, label [[WHILE_END:%.*]], label [[WHILE_BODY:%.*]] |
| ; CHECK: while.body: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: while.end: |
| ; CHECK-NEXT: [[TMP]] = add i32 [[N_ADDR_0]], [[ANS_0]] |
| ; CHECK-NEXT: br label [[FOR_INC]] |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: [[INC1]] = add nuw nsw i32 [[I_0]], 1 |
| ; CHECK-NEXT: br label [[FOR_COND]] |
| ; CHECK: for.end: |
| ; CHECK-NEXT: ret i32 [[ANS_0_LCSSA]] |
| ; |
| entry: |
| br label %for.cond |
| |
| for.cond: ; preds = %for.inc, %entry |
| %i.0 = phi i32 [ 0, %entry ], [ %inc1, %for.inc ] |
| %ans.0 = phi i32 [ 0, %entry ], [ %tmp, %for.inc ] |
| %n.addr.0 = phi i32 [ %n, %entry ], [ -1, %for.inc ] |
| %cmp = icmp slt i32 %i.0, %n.addr.0 |
| br i1 %cmp, label %for.body, label %for.cond.cleanup |
| |
| for.cond.cleanup: ; preds = %for.cond |
| %ans.0.lcssa = phi i32 [ %ans.0, %for.cond ] |
| br label %for.end |
| |
| for.body: ; preds = %for.cond |
| br label %while.cond |
| |
| while.cond: ; preds = %while.body, %for.body |
| br i1 true, label %while.end, label %while.body |
| |
| while.body: ; preds = %while.cond |
| br label %while.cond |
| |
| while.end: ; preds = %while.cond |
| %tmp = add i32 %n.addr.0, %ans.0 |
| br label %for.inc |
| |
| for.inc: ; preds = %while.end |
| %inc1 = add nuw nsw i32 %i.0, 1 |
| br label %for.cond |
| |
| for.end: ; preds = %for.cond.cleanup |
| ret i32 %ans.0.lcssa |
| } |
| |
| |
| ; TEST 18 (negative case) |
| ; int bounded_loop_inside_unbounded_loop(int n) { |
| ; int ans = 0; |
| ; while (n++) { |
| ; for (int i = 0; i < n; i++) { |
| ; ans++; |
| ; } |
| ; } |
| ; return ans; |
| ; } |
| |
| ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone |
| ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone |
| ; CHECK-NOT: willreturn |
| define i32 @bounded_loop_inside_unbounded_loop(i32 %n) { |
| ; CHECK-LABEL: define {{[^@]+}}@bounded_loop_inside_unbounded_loop |
| ; CHECK-SAME: (i32 [[N:%.*]]) |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[WHILE_COND:%.*]] |
| ; CHECK: while.cond: |
| ; CHECK-NEXT: [[ANS_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2:%.*]], [[FOR_END:%.*]] ] |
| ; CHECK-NEXT: [[N_ADDR_0:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ [[INC:%.*]], [[FOR_END]] ] |
| ; CHECK-NEXT: [[TMP:%.*]] = icmp sgt i32 [[N_ADDR_0]], -1 |
| ; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP]], i32 [[N_ADDR_0]], i32 -1 |
| ; CHECK-NEXT: [[INC]] = add nsw i32 [[N_ADDR_0]], 1 |
| ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[N_ADDR_0]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL]], label [[WHILE_END:%.*]], label [[WHILE_BODY:%.*]] |
| ; CHECK: while.body: |
| ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[ANS_0]], 1 |
| ; CHECK-NEXT: br label [[FOR_COND:%.*]] |
| ; CHECK: for.cond: |
| ; CHECK-NEXT: br i1 true, label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY:%.*]] |
| ; CHECK: for.cond.cleanup: |
| ; CHECK-NEXT: [[TMP2]] = add i32 [[TMP1]], [[SMAX]] |
| ; CHECK-NEXT: br label [[FOR_END]] |
| ; CHECK: for.body: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: for.inc: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: for.end: |
| ; CHECK-NEXT: br label [[WHILE_COND]] |
| ; CHECK: while.end: |
| ; CHECK-NEXT: [[ANS_0_LCSSA:%.*]] = phi i32 [ [[ANS_0]], [[WHILE_COND]] ] |
| ; CHECK-NEXT: ret i32 [[ANS_0_LCSSA]] |
| ; |
| entry: |
| br label %while.cond |
| |
| while.cond: ; preds = %for.end, %entry |
| %ans.0 = phi i32 [ 0, %entry ], [ %tmp2, %for.end ] |
| %n.addr.0 = phi i32 [ %n, %entry ], [ %inc, %for.end ] |
| %tmp = icmp sgt i32 %n.addr.0, -1 |
| %smax = select i1 %tmp, i32 %n.addr.0, i32 -1 |
| %inc = add nsw i32 %n.addr.0, 1 |
| %tobool = icmp eq i32 %n.addr.0, 0 |
| br i1 %tobool, label %while.end, label %while.body |
| |
| while.body: ; preds = %while.cond |
| %tmp1 = add i32 %ans.0, 1 |
| br label %for.cond |
| |
| for.cond: ; preds = %for.inc, %while.body |
| br i1 true, label %for.cond.cleanup, label %for.body |
| |
| for.cond.cleanup: ; preds = %for.cond |
| %tmp2 = add i32 %tmp1, %smax |
| br label %for.end |
| |
| for.body: ; preds = %for.cond |
| br label %for.inc |
| |
| for.inc: ; preds = %for.body |
| br label %for.cond |
| |
| for.end: ; preds = %for.cond.cleanup |
| br label %while.cond |
| |
| while.end: ; preds = %while.cond |
| %ans.0.lcssa = phi i32 [ %ans.0, %while.cond ] |
| ret i32 %ans.0.lcssa |
| } |
| |
| |
| ; TEST 19 (negative case) |
| ; int nested_unbounded_loops(int n) { |
| ; int ans = 0; |
| ; while (n--) { |
| ; while (n--) { |
| ; ans++; |
| ; } |
| ; while (n--) { |
| ; ans++; |
| ; } |
| ; } |
| ; return ans; |
| ; } |
| |
| ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone |
| ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone |
| ; CHECK-NOT: willreturn |
| define i32 @nested_unbounded_loops(i32 %n) { |
| ; CHECK-LABEL: define {{[^@]+}}@nested_unbounded_loops |
| ; CHECK-SAME: (i32 [[N:%.*]]) |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[WHILE_COND:%.*]] |
| ; CHECK: while.cond: |
| ; CHECK-NEXT: [[ANS_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP1:%.*]], [[WHILE_END10:%.*]] ] |
| ; CHECK-NEXT: [[N_ADDR_0:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ -1, [[WHILE_END10]] ] |
| ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[N_ADDR_0]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL]], label [[WHILE_END11:%.*]], label [[WHILE_BODY:%.*]] |
| ; CHECK: while.body: |
| ; CHECK-NEXT: br label [[WHILE_COND1:%.*]] |
| ; CHECK: while.cond1: |
| ; CHECK-NEXT: br i1 true, label [[WHILE_END:%.*]], label [[WHILE_BODY4:%.*]] |
| ; CHECK: while.body4: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: while.end: |
| ; CHECK-NEXT: [[TMP:%.*]] = add i32 [[N_ADDR_0]], -2 |
| ; CHECK-NEXT: br label [[WHILE_COND5:%.*]] |
| ; CHECK: while.cond5: |
| ; CHECK-NEXT: br i1 true, label [[WHILE_END10]], label [[WHILE_BODY8:%.*]] |
| ; CHECK: while.body8: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: while.end10: |
| ; CHECK-NEXT: [[TMP1]] = add i32 [[TMP]], [[ANS_0]] |
| ; CHECK-NEXT: br label [[WHILE_COND]] |
| ; CHECK: while.end11: |
| ; CHECK-NEXT: [[ANS_0_LCSSA:%.*]] = phi i32 [ [[ANS_0]], [[WHILE_COND]] ] |
| ; CHECK-NEXT: ret i32 [[ANS_0_LCSSA]] |
| ; |
| entry: |
| br label %while.cond |
| |
| while.cond: ; preds = %while.end10, %entry |
| %ans.0 = phi i32 [ 0, %entry ], [ %tmp1, %while.end10 ] |
| %n.addr.0 = phi i32 [ %n, %entry ], [ -1, %while.end10 ] |
| %tobool = icmp eq i32 %n.addr.0, 0 |
| br i1 %tobool, label %while.end11, label %while.body |
| |
| while.body: ; preds = %while.cond |
| br label %while.cond1 |
| |
| while.cond1: ; preds = %while.body4, %while.body |
| br i1 true, label %while.end, label %while.body4 |
| |
| while.body4: ; preds = %while.cond1 |
| br label %while.cond1 |
| |
| while.end: ; preds = %while.cond1 |
| %tmp = add i32 %n.addr.0, -2 |
| br label %while.cond5 |
| |
| while.cond5: ; preds = %while.body8, %while.end |
| br i1 true, label %while.end10, label %while.body8 |
| |
| while.body8: ; preds = %while.cond5 |
| br label %while.cond5 |
| |
| while.end10: ; preds = %while.cond5 |
| %tmp1 = add i32 %tmp, %ans.0 |
| br label %while.cond |
| |
| while.end11: ; preds = %while.cond |
| %ans.0.lcssa = phi i32 [ %ans.0, %while.cond ] |
| ret i32 %ans.0.lcssa |
| } |
| |
| |
| ; TEST 20 (negative case) |
| ; void non_loop_cycle(int n) { |
| ; if (fact_loop(n)>5) |
| ; goto entry1; |
| ; else |
| ; goto entry2; |
| ; |
| ; entry1: |
| ; if (fact_loop(n)>5) |
| ; goto exit; |
| ; else |
| ; goto entry2; |
| ; entry2: |
| ; if (fact_loop(n)>5) |
| ; goto exit; |
| ; else |
| ; goto entry1; |
| ; exit: |
| ; return; |
| ; } |
| |
| ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone |
| ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone |
| ; CHECK-NOT: willreturn |
| define void @non_loop_cycle(i32 %n) { |
| ; CHECK-LABEL: define {{[^@]+}}@non_loop_cycle |
| ; CHECK-SAME: (i32 [[N:%.*]]) |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CALL:%.*]] = call i32 @fact_loop(i32 [[N]]) |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[CALL]], 5 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: br label [[ENTRY1:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: br label [[ENTRY2:%.*]] |
| ; CHECK: entry1: |
| ; CHECK-NEXT: [[CALL1:%.*]] = call i32 @fact_loop(i32 [[N]]) |
| ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[CALL1]], 5 |
| ; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]] |
| ; CHECK: if.then3: |
| ; CHECK-NEXT: br label [[EXIT:%.*]] |
| ; CHECK: if.else4: |
| ; CHECK-NEXT: br label [[ENTRY2]] |
| ; CHECK: entry2: |
| ; CHECK-NEXT: [[CALL5:%.*]] = call i32 @fact_loop(i32 [[N]]) |
| ; CHECK-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[CALL5]], 5 |
| ; CHECK-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]] |
| ; CHECK: if.then7: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: if.else8: |
| ; CHECK-NEXT: br label [[ENTRY1]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %call = call i32 @fact_loop(i32 %n) |
| %cmp = icmp sgt i32 %call, 5 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: ; preds = %entry |
| br label %entry1 |
| |
| if.else: ; preds = %entry |
| br label %entry2 |
| |
| entry1: ; preds = %if.else8, %if.then |
| %call1 = call i32 @fact_loop(i32 %n) |
| %cmp2 = icmp sgt i32 %call1, 5 |
| br i1 %cmp2, label %if.then3, label %if.else4 |
| |
| if.then3: ; preds = %entry1 |
| br label %exit |
| |
| if.else4: ; preds = %entry1 |
| br label %entry2 |
| |
| entry2: ; preds = %if.else4, %if.else |
| %call5 = call i32 @fact_loop(i32 %n) |
| %cmp6 = icmp sgt i32 %call5, 5 |
| br i1 %cmp6, label %if.then7, label %if.else8 |
| |
| if.then7: ; preds = %entry2 |
| br label %exit |
| |
| if.else8: ; preds = %entry2 |
| br label %entry1 |
| |
| exit: ; preds = %if.then7, %if.then3 |
| ret void |
| } |
| |
| attributes #0 = { nounwind uwtable noinline } |
| attributes #1 = { uwtable noinline } |