blob: defb061c73e6a1f85c6d07511177c6b367490e0e [file] [log] [blame]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes
; RUN: opt -passes=function-attrs -S %s | FileCheck %s
define void @mustprogress_readnone() mustprogress {
; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(none)
; CHECK-LABEL: @mustprogress_readnone(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: br label [[WHILE_BODY]]
;
entry:
br label %while.body
while.body:
br label %while.body
}
define i32 @mustprogress_load(ptr %ptr) mustprogress {
; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: @mustprogress_load(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: [[R:%.*]] = load i32, ptr [[PTR:%.*]], align 4
; CHECK-NEXT: br label [[WHILE_BODY]]
;
entry:
br label %while.body
while.body:
%r = load i32, ptr %ptr
br label %while.body
}
define void @mustprogress_store(ptr %ptr) mustprogress {
; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind memory(argmem: write)
; CHECK-LABEL: @mustprogress_store(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
; CHECK-NEXT: br label [[WHILE_BODY]]
;
entry:
br label %while.body
while.body:
store i32 0, ptr %ptr
br label %while.body
}
declare void @unknown_fn()
define void @mustprogress_call_unknown_fn() mustprogress {
; CHECK: Function Attrs: mustprogress
; CHECK-LABEL: @mustprogress_call_unknown_fn(
; CHECK-NEXT: call void @unknown_fn()
; CHECK-NEXT: ret void
;
call void @unknown_fn()
ret void
}
define i32 @mustprogress_call_known_functions(ptr %ptr) mustprogress {
; CHECK: Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind willreturn memory(argmem: read)
; CHECK-LABEL: @mustprogress_call_known_functions(
; CHECK-NEXT: call void @mustprogress_readnone()
; CHECK-NEXT: [[R:%.*]] = call i32 @mustprogress_load(ptr [[PTR:%.*]])
; CHECK-NEXT: ret i32 [[R]]
;
call void @mustprogress_readnone()
%r = call i32 @mustprogress_load(ptr %ptr)
ret i32 %r
}
declare i32 @__gxx_personality_v0(...)
define i64 @mustprogress_mayunwind() mustprogress personality ptr @__gxx_personality_v0 {
; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
; CHECK-LABEL: @mustprogress_mayunwind(
; CHECK-NEXT: [[A:%.*]] = invoke i64 @fn_noread()
; CHECK-NEXT: to label [[A:%.*]] unwind label [[B:%.*]]
; CHECK: A:
; CHECK-NEXT: ret i64 10
; CHECK: B:
; CHECK-NEXT: [[VAL:%.*]] = landingpad { ptr, i32 }
; CHECK-NEXT: catch ptr null
; CHECK-NEXT: ret i64 0
;
%a = invoke i64 @fn_noread()
to label %A unwind label %B
A:
ret i64 10
B:
%val = landingpad { ptr, i32 }
catch ptr null
ret i64 0
}
; Function without loops or non-willreturn calls will return.
define void @willreturn_no_loop(i1 %c, ptr %p) {
; CHECK: Function Attrs: mustprogress willreturn
; CHECK-LABEL: @willreturn_no_loop(
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
; CHECK: if:
; CHECK-NEXT: [[TMP1:%.*]] = load atomic i32, ptr [[P:%.*]] seq_cst, align 4
; CHECK-NEXT: call void @fn_willreturn()
; CHECK-NEXT: br label [[END:%.*]]
; CHECK: else:
; CHECK-NEXT: store atomic i32 0, ptr [[P]] seq_cst, align 4
; CHECK-NEXT: br label [[END]]
; CHECK: end:
; CHECK-NEXT: ret void
;
br i1 %c, label %if, label %else
if:
load atomic i32, ptr %p seq_cst, align 4
call void @fn_willreturn()
br label %end
else:
store atomic i32 0, ptr %p seq_cst, align 4
br label %end
end:
ret void
}
; Calls a function that is not guaranteed to return, not willreturn.
define void @willreturn_non_returning_function(i1 %c, ptr %p) {
; CHECK-LABEL: @willreturn_non_returning_function(
; CHECK-NEXT: call void @unknown_fn()
; CHECK-NEXT: ret void
;
call void @unknown_fn()
ret void
}
; Infinite loop without mustprogress, will not return.
define void @willreturn_loop() {
; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none)
; CHECK-LABEL: @willreturn_loop(
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: br label [[LOOP]]
;
br label %loop
loop:
br label %loop
}
; Finite loop. Could be willreturn but not detected.
; FIXME
define void @willreturn_finite_loop() {
; CHECK: Function Attrs: nofree norecurse nosync nounwind memory(none)
; CHECK-LABEL: @willreturn_finite_loop(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[I_INC]] = add nuw i32 [[I]], 1
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[I_INC]], 100
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[END:%.*]]
; CHECK: end:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%i = phi i32 [ 0, %entry], [ %i.inc, %loop ]
%i.inc = add nuw i32 %i, 1
%c = icmp ne i32 %i.inc, 100
br i1 %c, label %loop, label %end
end:
ret void
}
; Infinite recursion without mustprogress, will not return.
define void @willreturn_recursion() {
; CHECK: Function Attrs: nofree nosync nounwind memory(none)
; CHECK-LABEL: @willreturn_recursion(
; CHECK-NEXT: tail call void @willreturn_recursion()
; CHECK-NEXT: ret void
;
tail call void @willreturn_recursion()
ret void
}
; Irreducible infinite loop, will not return.
define void @willreturn_irreducible(i1 %c) {
; CHECK: Function Attrs: nofree norecurse noreturn nosync nounwind memory(none)
; CHECK-LABEL: @willreturn_irreducible(
; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br label [[BB2]]
; CHECK: bb2:
; CHECK-NEXT: br label [[BB1]]
;
br i1 %c, label %bb1, label %bb2
bb1:
br label %bb2
bb2:
br label %bb1
}
define linkonce i32 @square(i32) {
; CHECK-LABEL: @square(
; CHECK-NEXT: [[TMP2:%.*]] = mul nsw i32 [[TMP0:%.*]], [[TMP0]]
; CHECK-NEXT: ret i32 [[TMP2]]
;
%2 = mul nsw i32 %0, %0
ret i32 %2
}
declare i64 @fn_noread() readnone
declare void @fn_willreturn() willreturn