llvm/llvm/test/Transforms/Attributor/willreturn.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-annotate-decl-cs  -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC

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)
define void @only_return() #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@only_return
; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
; 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
define i32 @fib(i32 %0) local_unnamed_addr #0 {
; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
; TUNIT-LABEL: define {{[^@]+}}@fib
; TUNIT-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
; TUNIT-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 2
; TUNIT-NEXT:    br i1 [[TMP2]], label [[TMP9:%.*]], label [[TMP3:%.*]]
; TUNIT:       3:
; TUNIT-NEXT:    [[TMP4:%.*]] = add nsw i32 [[TMP0]], -1
; TUNIT-NEXT:    [[TMP5:%.*]] = tail call i32 @fib(i32 [[TMP4]]) #[[ATTR27:[0-9]+]]
; TUNIT-NEXT:    [[TMP6:%.*]] = add nsw i32 [[TMP0]], -2
; TUNIT-NEXT:    [[TMP7:%.*]] = tail call i32 @fib(i32 [[TMP6]]) #[[ATTR27]]
; TUNIT-NEXT:    [[TMP8:%.*]] = add nsw i32 [[TMP7]], [[TMP5]]
; TUNIT-NEXT:    ret i32 [[TMP8]]
; TUNIT:       9:
; TUNIT-NEXT:    ret i32 [[TMP0]]
;
; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
; CGSCC-LABEL: define {{[^@]+}}@fib
; CGSCC-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
; CGSCC-NEXT:    [[TMP2:%.*]] = icmp slt i32 [[TMP0]], 2
; CGSCC-NEXT:    br i1 [[TMP2]], label [[TMP9:%.*]], label [[TMP3:%.*]]
; CGSCC:       3:
; CGSCC-NEXT:    [[TMP4:%.*]] = add nsw i32 [[TMP0]], -1
; CGSCC-NEXT:    [[TMP5:%.*]] = tail call i32 @fib(i32 [[TMP4]]) #[[ATTR19:[0-9]+]]
; CGSCC-NEXT:    [[TMP6:%.*]] = add nsw i32 [[TMP0]], -2
; CGSCC-NEXT:    [[TMP7:%.*]] = tail call i32 @fib(i32 [[TMP6]]) #[[ATTR19]]
; CGSCC-NEXT:    [[TMP8:%.*]] = add nsw i32 [[TMP7]], [[TMP5]]
; CGSCC-NEXT:    ret i32 [[TMP8]]
; CGSCC:       9:
; CGSCC-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.

define i32 @fact_maybe_not_halt(i32 %0) local_unnamed_addr #0 {
; CHECK: Function Attrs: nofree noinline norecurse nosync nounwind memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@fact_maybe_not_halt
; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
; 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;
; }

define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@fact_loop
; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
; 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

define void @mutual_recursion1(i1 %c) #0 {
; CHECK: Function Attrs: nofree noinline nosync nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@mutual_recursion1
; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR4:[0-9]+]] {
; CHECK-NEXT:    br i1 [[C]], label [[REC:%.*]], label [[END:%.*]]
; CHECK:       rec:
; CHECK-NEXT:    call void @sink() #[[ATTR28:[0-9]+]]
; CHECK-NEXT:    call void @mutual_recursion2(i1 noundef [[C]]) #[[ATTR29:[0-9]+]]
; 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
}


define void @mutual_recursion2(i1 %c) #0 {
; CHECK: Function Attrs: nofree noinline nosync nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@mutual_recursion2
; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR4]] {
; CHECK-NEXT:    call void @mutual_recursion1(i1 noundef [[C]]) #[[ATTR29]]
; 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
declare void @exit(i32 %0) local_unnamed_addr noreturn

define void @only_exit() local_unnamed_addr #0 {
; CHECK: Function Attrs: noinline noreturn nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@only_exit
; CHECK-SAME: () local_unnamed_addr #[[ATTR6:[0-9]+]] {
; CHECK-NEXT:    tail call void @exit(i32 noundef 0) #[[ATTR5:[0-9]+]]
; 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;
; }
define void @conditional_exit(i32 %0, ptr nocapture readonly %1) local_unnamed_addr #0 {
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@conditional_exit
; CHECK-SAME: (i32 [[TMP0:%.*]], ptr nocapture nofree readonly [[TMP1:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
; 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 noundef 0) #[[ATTR5]]
; CHECK-NEXT:    unreachable
; CHECK:       5:
; CHECK-NEXT:    [[TMP6:%.*]] = load i32, ptr [[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 noundef 1) #[[ATTR5]]
; 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, ptr %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: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.floor.f32(float)

define void @call_floor(float %a) #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@call_floor
; CHECK-SAME: (float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    ret void
;
  tail call float @llvm.floor.f32(float %a)
  ret void
}

define float @call_floor2(float %a) #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@call_floor2
; CHECK-SAME: (float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT:    [[C:%.*]] = tail call nofpclass(sub) float @llvm.floor.f32(float [[A]]) #[[ATTR30:[0-9]+]]
; 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
declare void @maybe_noreturn() #0

define void @call_maybe_noreturn() #0 {
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@call_maybe_noreturn
; CHECK-SAME: () #[[ATTR7]] {
; CHECK-NEXT:    tail call void @maybe_noreturn() #[[ATTR31:[0-9]+]]
; CHECK-NEXT:    ret void
;
  tail call void @maybe_noreturn()
  ret void
}


; TEST 8 (positive case)
; Check propagation.

; CHECK: Function Attrs: norecurse willreturn
declare void @will_return() willreturn norecurse

define void @f1() #0 {
; CHECK: Function Attrs: mustprogress noinline nounwind willreturn uwtable
; CHECK-LABEL: define {{[^@]+}}@f1
; CHECK-SAME: () #[[ATTR10:[0-9]+]] {
; CHECK-NEXT:    tail call void @will_return() #[[ATTR32:[0-9]+]]
; CHECK-NEXT:    ret void
;
  tail call void @will_return()
  ret void
}

define void @f2() #0 {
; CHECK: Function Attrs: mustprogress noinline nounwind willreturn uwtable
; CHECK-LABEL: define {{[^@]+}}@f2
; CHECK-SAME: () #[[ATTR10]] {
; CHECK-NEXT:    tail call void @f1() #[[ATTR33:[0-9]+]]
; CHECK-NEXT:    ret void
;
  tail call void @f1()
  ret void
}


; TEST 9 (negative case)
; call willreturn function in endless loop.

define void @call_will_return_but_has_loop() #0 {
; CHECK: Function Attrs: noinline noreturn nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@call_will_return_but_has_loop
; CHECK-SAME: () #[[ATTR6]] {
; 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 willreturn uwtable
declare i1 @maybe_raise_exception() #1 willreturn

define void @invoke_test() personality ptr @__gxx_personality_v0 {
; CHECK: Function Attrs: mustprogress nounwind willreturn
; CHECK-LABEL: define {{[^@]+}}@invoke_test
; CHECK-SAME: () #[[ATTR12:[0-9]+]] personality ptr @__gxx_personality_v0 {
; CHECK-NEXT:    [[TMP1:%.*]] = invoke i1 @maybe_raise_exception() #[[ATTR32]]
; CHECK-NEXT:            to label [[N:%.*]] unwind label [[F:%.*]]
; CHECK:       N:
; CHECK-NEXT:    ret void
; CHECK:       F:
; CHECK-NEXT:    [[VAL:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT:            catch ptr null
; CHECK-NEXT:    ret void
;
  invoke i1 @maybe_raise_exception()
  to label %N unwind label %F
  N:
  ret void
  F:
  %val = landingpad { ptr, i32 }
  catch ptr 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;
; }

define i32 @loop_constant_trip_count(ptr nocapture readonly %0) #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable
; CHECK-LABEL: define {{[^@]+}}@loop_constant_trip_count
; CHECK-SAME: (ptr nocapture nofree nonnull readonly dereferenceable(4) [[TMP0:%.*]]) #[[ATTR13:[0-9]+]] {
; CHECK-NEXT:    br label [[TMP3:%.*]]
; CHECK:       2:
; CHECK-NEXT:    ret i32 [[TMP8:%.*]]
; CHECK:       3:
; CHECK-NEXT:    [[TMP4:%.*]] = phi i64 [ 0, [[TMP1:%.*]] ], [ [[TMP9:%.*]], [[TMP3]] ]
; CHECK-NEXT:    [[TMP5:%.*]] = phi i32 [ 0, [[TMP1]] ], [ [[TMP8]], [[TMP3]] ]
; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i64 [[TMP4]]
; CHECK-NEXT:    [[TMP7:%.*]] = load i32, ptr [[TMP6]], align 4
; CHECK-NEXT:    [[TMP8]] = add nsw i32 [[TMP7]], [[TMP5]]
; CHECK-NEXT:    [[TMP9]] = add nuw nsw i64 [[TMP4]], 1
; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 10
; CHECK-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, ptr %0, i64 %4
  %7 = load i32, ptr %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;
; }
define i32 @loop_trip_count_unbound(i32 %0, i32 %1, ptr nocapture readonly %2, i32 %3) local_unnamed_addr #0 {
; CHECK: Function Attrs: nofree noinline norecurse nosync nounwind memory(argmem: read) uwtable
; CHECK-LABEL: define {{[^@]+}}@loop_trip_count_unbound
; CHECK-SAME: (i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], ptr nocapture nofree readonly [[TMP2:%.*]], i32 [[TMP3:%.*]]) local_unnamed_addr #[[ATTR14:[0-9]+]] {
; 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, ptr [[TMP2]], i64 [[TMP11]]
; CHECK-NEXT:    [[TMP13:%.*]] = load i32, ptr [[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, ptr %2, i64 %11
  %13 = load i32, ptr %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;
;  }


define i32 @loop_trip_dec(i32 %0, ptr nocapture readonly %1) local_unnamed_addr #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable
; CHECK-LABEL: define {{[^@]+}}@loop_trip_dec
; CHECK-SAME: (i32 [[TMP0:%.*]], ptr nocapture nofree readonly [[TMP1:%.*]]) local_unnamed_addr #[[ATTR13]] {
; 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, ptr [[TMP1]], i64 [[TMP7]]
; CHECK-NEXT:    [[TMP10:%.*]] = load i32, ptr [[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, ptr %1, i64 %7
  %10 = load i32, ptr %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

define i32 @multiple_return(i32 %a) #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@multiple_return
; CHECK-SAME: (i32 [[A:%.*]]) #[[ATTR0]] {
; 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)
define void @unreachable_exit_positive1() #0 {
; CHECK: Function Attrs: mustprogress noinline nounwind willreturn uwtable
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_positive1
; CHECK-SAME: () #[[ATTR10]] {
; CHECK-NEXT:    tail call void @will_return() #[[ATTR32]]
; 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
}

define i32 @unreachable_exit_positive2(i32) local_unnamed_addr #0 {
; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_positive2
; CHECK-SAME: (i32 [[TMP0:%.*]]) local_unnamed_addr #[[ATTR0]] {
; 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

define void @unreachable_exit_negative1() #0 {
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_negative1
; CHECK-SAME: () #[[ATTR7]] {
; CHECK-NEXT:    tail call void @exit(i32 noundef 0) #[[ATTR5]]
; 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
}

define void @unreachable_exit_negative2() #0 {
; CHECK: Function Attrs: nofree noinline norecurse noreturn nosync nounwind memory(none) uwtable
; CHECK-LABEL: define {{[^@]+}}@unreachable_exit_negative2
; CHECK-SAME: () #[[ATTR15:[0-9]+]] {
; 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
declare void @llvm.eh.sjlj.longjmp(ptr)

define void @call_longjmp(ptr nocapture readnone %0) local_unnamed_addr #0 {
; CHECK: Function Attrs: noinline nounwind uwtable
; CHECK-LABEL: define {{[^@]+}}@call_longjmp
; CHECK-SAME: (ptr nocapture nofree readnone [[TMP0:%.*]]) local_unnamed_addr #[[ATTR7]] {
; CHECK-NEXT:    tail call void @llvm.eh.sjlj.longjmp(ptr noalias nofree readnone [[TMP0]]) #[[ATTR5]]
; CHECK-NEXT:    unreachable
;
  tail call void @llvm.eh.sjlj.longjmp(ptr %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;
; }

define i32 @infinite_loop_inside_bounded_loop(i32 %n) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind memory(none)
; CHECK-LABEL: define {{[^@]+}}@infinite_loop_inside_bounded_loop
; CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR17:[0-9]+]] {
; 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;
; }

define i32 @bounded_nested_loops(i32 %n) {
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@bounded_nested_loops
; CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR18:[0-9]+]] {
; 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]]
;
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;
; }

define i32 @bounded_loop_inside_unbounded_loop(i32 %n) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind memory(none)
; CHECK-LABEL: define {{[^@]+}}@bounded_loop_inside_unbounded_loop
; CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR17]] {
; 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]]
;
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;
; }

define i32 @nested_unbounded_loops(i32 %n) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind memory(none)
; CHECK-LABEL: define {{[^@]+}}@nested_unbounded_loops
; CHECK-SAME: (i32 [[N:%.*]]) #[[ATTR17]] {
; 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]]
;
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;
;    }

define void @non_loop_cycle(i32 %n) {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(none)
; TUNIT-LABEL: define {{[^@]+}}@non_loop_cycle
; TUNIT-SAME: (i32 [[N:%.*]]) #[[ATTR17]] {
; TUNIT-NEXT:  entry:
; TUNIT-NEXT:    [[CALL:%.*]] = call i32 @fact_loop(i32 [[N]]) #[[ATTR27]]
; TUNIT-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CALL]], 5
; TUNIT-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; TUNIT:       if.then:
; TUNIT-NEXT:    br label [[ENTRY1:%.*]]
; TUNIT:       if.else:
; TUNIT-NEXT:    br label [[ENTRY2:%.*]]
; TUNIT:       entry1:
; TUNIT-NEXT:    [[CALL1:%.*]] = call i32 @fact_loop(i32 [[N]]) #[[ATTR27]]
; TUNIT-NEXT:    [[CMP2:%.*]] = icmp sgt i32 [[CALL1]], 5
; TUNIT-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]]
; TUNIT:       if.then3:
; TUNIT-NEXT:    br label [[EXIT:%.*]]
; TUNIT:       if.else4:
; TUNIT-NEXT:    br label [[ENTRY2]]
; TUNIT:       entry2:
; TUNIT-NEXT:    [[CALL5:%.*]] = call i32 @fact_loop(i32 [[N]]) #[[ATTR27]]
; TUNIT-NEXT:    [[CMP6:%.*]] = icmp sgt i32 [[CALL5]], 5
; TUNIT-NEXT:    br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]]
; TUNIT:       if.then7:
; TUNIT-NEXT:    br label [[EXIT]]
; TUNIT:       if.else8:
; TUNIT-NEXT:    br label [[ENTRY1]]
; TUNIT:       exit:
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: nofree nosync nounwind memory(none)
; CGSCC-LABEL: define {{[^@]+}}@non_loop_cycle
; CGSCC-SAME: (i32 [[N:%.*]]) #[[ATTR19]] {
; CGSCC-NEXT:  entry:
; CGSCC-NEXT:    [[CALL:%.*]] = call i32 @fact_loop(i32 [[N]]) #[[ATTR34:[0-9]+]]
; CGSCC-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CALL]], 5
; CGSCC-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CGSCC:       if.then:
; CGSCC-NEXT:    br label [[ENTRY1:%.*]]
; CGSCC:       if.else:
; CGSCC-NEXT:    br label [[ENTRY2:%.*]]
; CGSCC:       entry1:
; CGSCC-NEXT:    [[CALL1:%.*]] = call i32 @fact_loop(i32 [[N]]) #[[ATTR34]]
; CGSCC-NEXT:    [[CMP2:%.*]] = icmp sgt i32 [[CALL1]], 5
; CGSCC-NEXT:    br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]]
; CGSCC:       if.then3:
; CGSCC-NEXT:    br label [[EXIT:%.*]]
; CGSCC:       if.else4:
; CGSCC-NEXT:    br label [[ENTRY2]]
; CGSCC:       entry2:
; CGSCC-NEXT:    [[CALL5:%.*]] = call i32 @fact_loop(i32 [[N]]) #[[ATTR34]]
; CGSCC-NEXT:    [[CMP6:%.*]] = icmp sgt i32 [[CALL5]], 5
; CGSCC-NEXT:    br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_ELSE8:%.*]]
; CGSCC:       if.then7:
; CGSCC-NEXT:    br label [[EXIT]]
; CGSCC:       if.else8:
; CGSCC-NEXT:    br label [[ENTRY1]]
; CGSCC:       exit:
; CGSCC-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
}

declare void @unknown()
declare void @readonly() readonly
declare void @readnone() readnone
declare void @unknown_mustprogress() mustprogress
declare void @readonly_mustprogress() readonly mustprogress

define void @willreturn_mustprogress_caller_1() mustprogress {
; TUNIT: Function Attrs: mustprogress
; TUNIT-LABEL: define {{[^@]+}}@willreturn_mustprogress_caller_1
; TUNIT-SAME: () #[[ATTR21:[0-9]+]] {
; TUNIT-NEXT:    call void @unknown()
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress
; CGSCC-LABEL: define {{[^@]+}}@willreturn_mustprogress_caller_1
; CGSCC-SAME: () #[[ATTR22:[0-9]+]] {
; CGSCC-NEXT:    call void @unknown()
; CGSCC-NEXT:    ret void
;
  call void @unknown()
  ret void
}
define void @willreturn_mustprogress_caller_2() mustprogress {
; TUNIT: Function Attrs: mustprogress nosync willreturn memory(read)
; TUNIT-LABEL: define {{[^@]+}}@willreturn_mustprogress_caller_2
; TUNIT-SAME: () #[[ATTR23:[0-9]+]] {
; TUNIT-NEXT:    call void @readonly() #[[ATTR34:[0-9]+]]
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress nosync willreturn memory(read)
; CGSCC-LABEL: define {{[^@]+}}@willreturn_mustprogress_caller_2
; CGSCC-SAME: () #[[ATTR24:[0-9]+]] {
; CGSCC-NEXT:    call void @readonly() #[[ATTR35:[0-9]+]]
; CGSCC-NEXT:    ret void
;
  call void @readonly()
  ret void
}
define void @willreturn_mustprogress_caller_3() mustprogress {
; TUNIT: Function Attrs: mustprogress nosync willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@willreturn_mustprogress_caller_3
; TUNIT-SAME: () #[[ATTR24:[0-9]+]] {
; TUNIT-NEXT:    call void @readnone() #[[ATTR35:[0-9]+]]
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress nosync willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@willreturn_mustprogress_caller_3
; CGSCC-SAME: () #[[ATTR25:[0-9]+]] {
; CGSCC-NEXT:    call void @readnone() #[[ATTR36:[0-9]+]]
; CGSCC-NEXT:    ret void
;
  call void @readnone()
  ret void
}
define void @willreturn_mustprogress_callee_1() {
; CHECK-LABEL: define {{[^@]+}}@willreturn_mustprogress_callee_1() {
; CHECK-NEXT:    call void @unknown_mustprogress()
; CHECK-NEXT:    ret void
;
  call void @unknown_mustprogress()
  ret void
}
define void @willreturn_mustprogress_callee_2() {
; TUNIT: Function Attrs: mustprogress nosync willreturn memory(read)
; TUNIT-LABEL: define {{[^@]+}}@willreturn_mustprogress_callee_2
; TUNIT-SAME: () #[[ATTR23]] {
; TUNIT-NEXT:    call void @readonly_mustprogress() #[[ATTR36:[0-9]+]]
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress nosync willreturn memory(read)
; CGSCC-LABEL: define {{[^@]+}}@willreturn_mustprogress_callee_2
; CGSCC-SAME: () #[[ATTR24]] {
; CGSCC-NEXT:    call void @readonly_mustprogress() #[[ATTR37:[0-9]+]]
; CGSCC-NEXT:    ret void
;
  call void @readonly_mustprogress()
  ret void
}
define void @willreturn_mustprogress_callee_3() {
; CHECK-LABEL: define {{[^@]+}}@willreturn_mustprogress_callee_3() {
; CHECK-NEXT:    call void @willreturn_mustprogress_callee_1()
; CHECK-NEXT:    ret void
;
  call void @willreturn_mustprogress_callee_1()
  ret void
}
define void @willreturn_mustprogress_callee_4() {
; TUNIT: Function Attrs: mustprogress nosync willreturn memory(read)
; TUNIT-LABEL: define {{[^@]+}}@willreturn_mustprogress_callee_4
; TUNIT-SAME: () #[[ATTR23]] {
; TUNIT-NEXT:    call void @willreturn_mustprogress_callee_2() #[[ATTR36]]
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress nosync willreturn memory(read)
; CGSCC-LABEL: define {{[^@]+}}@willreturn_mustprogress_callee_4
; CGSCC-SAME: () #[[ATTR24]] {
; CGSCC-NEXT:    call void @willreturn_mustprogress_callee_2() #[[ATTR38:[0-9]+]]
; CGSCC-NEXT:    ret void
;
  call void @willreturn_mustprogress_callee_2()
  ret void
}

define weak void @implied_mustprogress1() willreturn {
; TUNIT: Function Attrs: mustprogress willreturn
; TUNIT-LABEL: define {{[^@]+}}@implied_mustprogress1
; TUNIT-SAME: () #[[ATTR25:[0-9]+]] {
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress willreturn
; CGSCC-LABEL: define {{[^@]+}}@implied_mustprogress1
; CGSCC-SAME: () #[[ATTR26:[0-9]+]] {
; CGSCC-NEXT:    ret void
;
  ret void
}
define weak void @implied_willreturn1() readnone mustprogress {
; TUNIT: Function Attrs: mustprogress nosync willreturn memory(none)
; TUNIT-LABEL: define {{[^@]+}}@implied_willreturn1
; TUNIT-SAME: () #[[ATTR24]] {
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress nosync willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@implied_willreturn1
; CGSCC-SAME: () #[[ATTR25]] {
; CGSCC-NEXT:    ret void
;
  ret void
}
define weak void @implied_willreturn2() readonly mustprogress {
; TUNIT: Function Attrs: mustprogress nosync willreturn memory(read)
; TUNIT-LABEL: define {{[^@]+}}@implied_willreturn2
; TUNIT-SAME: () #[[ATTR23]] {
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress nosync willreturn memory(read)
; CGSCC-LABEL: define {{[^@]+}}@implied_willreturn2
; CGSCC-SAME: () #[[ATTR24]] {
; CGSCC-NEXT:    ret void
;
  ret void
}
define weak void @not_implied_willreturn1() mustprogress {
; TUNIT: Function Attrs: mustprogress
; TUNIT-LABEL: define {{[^@]+}}@not_implied_willreturn1
; TUNIT-SAME: () #[[ATTR21]] {
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: mustprogress
; CGSCC-LABEL: define {{[^@]+}}@not_implied_willreturn1
; CGSCC-SAME: () #[[ATTR22]] {
; CGSCC-NEXT:    ret void
;
  ret void
}
define weak void @not_implied_willreturn2() readnone {
; TUNIT: Function Attrs: nosync memory(none)
; TUNIT-LABEL: define {{[^@]+}}@not_implied_willreturn2
; TUNIT-SAME: () #[[ATTR26:[0-9]+]] {
; TUNIT-NEXT:    ret void
;
; CGSCC: Function Attrs: nosync memory(none)
; CGSCC-LABEL: define {{[^@]+}}@not_implied_willreturn2
; CGSCC-SAME: () #[[ATTR27:[0-9]+]] {
; CGSCC-NEXT:    ret void
;
  ret void
}

attributes #0 = { nounwind uwtable noinline }
attributes #1 = { uwtable noinline }
;.
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
; TUNIT: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
; TUNIT: attributes #[[ATTR2]] = { nofree noinline norecurse nosync nounwind memory(none) uwtable }
; TUNIT: attributes #[[ATTR3:[0-9]+]] = { nofree nosync nounwind willreturn }
; TUNIT: attributes #[[ATTR4]] = { nofree noinline nosync nounwind uwtable }
; TUNIT: attributes #[[ATTR5]] = { noreturn }
; TUNIT: attributes #[[ATTR6]] = { noinline noreturn nounwind uwtable }
; TUNIT: attributes #[[ATTR7]] = { noinline nounwind uwtable }
; TUNIT: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; TUNIT: attributes #[[ATTR9:[0-9]+]] = { norecurse willreturn }
; TUNIT: attributes #[[ATTR10]] = { mustprogress noinline nounwind willreturn uwtable }
; TUNIT: attributes #[[ATTR11:[0-9]+]] = { noinline willreturn uwtable }
; TUNIT: attributes #[[ATTR12]] = { mustprogress nounwind willreturn }
; TUNIT: attributes #[[ATTR13]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable }
; TUNIT: attributes #[[ATTR14]] = { nofree noinline norecurse nosync nounwind memory(argmem: read) uwtable }
; TUNIT: attributes #[[ATTR15]] = { nofree noinline norecurse noreturn nosync nounwind memory(none) uwtable }
; TUNIT: attributes #[[ATTR16:[0-9]+]] = { noreturn nounwind }
; TUNIT: attributes #[[ATTR17]] = { nofree norecurse nosync nounwind memory(none) }
; TUNIT: attributes #[[ATTR18]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; TUNIT: attributes #[[ATTR19:[0-9]+]] = { memory(read) }
; TUNIT: attributes #[[ATTR20:[0-9]+]] = { memory(none) }
; TUNIT: attributes #[[ATTR21]] = { mustprogress }
; TUNIT: attributes #[[ATTR22:[0-9]+]] = { mustprogress memory(read) }
; TUNIT: attributes #[[ATTR23]] = { mustprogress nosync willreturn memory(read) }
; TUNIT: attributes #[[ATTR24]] = { mustprogress nosync willreturn memory(none) }
; TUNIT: attributes #[[ATTR25]] = { mustprogress willreturn }
; TUNIT: attributes #[[ATTR26]] = { nosync memory(none) }
; TUNIT: attributes #[[ATTR27]] = { nofree nosync nounwind memory(none) }
; TUNIT: attributes #[[ATTR28]] = { nofree nounwind willreturn }
; TUNIT: attributes #[[ATTR29]] = { nofree nosync nounwind }
; TUNIT: attributes #[[ATTR30]] = { nofree nosync willreturn }
; TUNIT: attributes #[[ATTR31]] = { nounwind }
; TUNIT: attributes #[[ATTR32]] = { willreturn }
; TUNIT: attributes #[[ATTR33]] = { nounwind willreturn }
; TUNIT: attributes #[[ATTR34]] = { nosync memory(read) }
; TUNIT: attributes #[[ATTR35]] = { nosync }
; TUNIT: attributes #[[ATTR36]] = { nosync willreturn memory(read) }
;.
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
; CGSCC: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable }
; CGSCC: attributes #[[ATTR2]] = { nofree noinline norecurse nosync nounwind memory(none) uwtable }
; CGSCC: attributes #[[ATTR3:[0-9]+]] = { nofree nosync nounwind willreturn }
; CGSCC: attributes #[[ATTR4]] = { nofree noinline nosync nounwind uwtable }
; CGSCC: attributes #[[ATTR5]] = { noreturn }
; CGSCC: attributes #[[ATTR6]] = { noinline noreturn nounwind uwtable }
; CGSCC: attributes #[[ATTR7]] = { noinline nounwind uwtable }
; CGSCC: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CGSCC: attributes #[[ATTR9:[0-9]+]] = { norecurse willreturn }
; CGSCC: attributes #[[ATTR10]] = { mustprogress noinline nounwind willreturn uwtable }
; CGSCC: attributes #[[ATTR11:[0-9]+]] = { noinline willreturn uwtable }
; CGSCC: attributes #[[ATTR12]] = { mustprogress nounwind willreturn }
; CGSCC: attributes #[[ATTR13]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable }
; CGSCC: attributes #[[ATTR14]] = { nofree noinline norecurse nosync nounwind memory(argmem: read) uwtable }
; CGSCC: attributes #[[ATTR15]] = { nofree noinline norecurse noreturn nosync nounwind memory(none) uwtable }
; CGSCC: attributes #[[ATTR16:[0-9]+]] = { noreturn nounwind }
; CGSCC: attributes #[[ATTR17]] = { nofree norecurse nosync nounwind memory(none) }
; CGSCC: attributes #[[ATTR18]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR19]] = { nofree nosync nounwind memory(none) }
; CGSCC: attributes #[[ATTR20:[0-9]+]] = { memory(read) }
; CGSCC: attributes #[[ATTR21:[0-9]+]] = { memory(none) }
; CGSCC: attributes #[[ATTR22]] = { mustprogress }
; CGSCC: attributes #[[ATTR23:[0-9]+]] = { mustprogress memory(read) }
; CGSCC: attributes #[[ATTR24]] = { mustprogress nosync willreturn memory(read) }
; CGSCC: attributes #[[ATTR25]] = { mustprogress nosync willreturn memory(none) }
; CGSCC: attributes #[[ATTR26]] = { mustprogress willreturn }
; CGSCC: attributes #[[ATTR27]] = { nosync memory(none) }
; CGSCC: attributes #[[ATTR28]] = { nofree nounwind willreturn }
; CGSCC: attributes #[[ATTR29]] = { nofree nosync nounwind }
; CGSCC: attributes #[[ATTR30]] = { nofree nosync willreturn }
; CGSCC: attributes #[[ATTR31]] = { nounwind }
; CGSCC: attributes #[[ATTR32]] = { willreturn }
; CGSCC: attributes #[[ATTR33]] = { nounwind willreturn }
; CGSCC: attributes #[[ATTR34]] = { nofree nosync }
; CGSCC: attributes #[[ATTR35]] = { nosync memory(read) }
; CGSCC: attributes #[[ATTR36]] = { nosync }
; CGSCC: attributes #[[ATTR37]] = { nosync willreturn memory(read) }
; CGSCC: attributes #[[ATTR38]] = { willreturn memory(read) }
;.