; 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) }
;.