if (CB->hasFnAttr(Attribute::WillReturn))
return true;
- // Non-throwing call sites can loop infinitely, call exit/pthread_exit
- // etc. and thus not return. However, LLVM already assumes that
- //
- // - Thread exiting actions are modeled as writes to memory invisible to
- // the program.
- //
- // - Loops that don't have side effects (side effects are volatile/atomic
- // stores and IO) always terminate (see http://llvm.org/PR965).
- // Furthermore IO itself is also modeled as writes to memory invisible to
- // the program.
- //
- // We rely on those assumptions here, and use the memory effects of the call
- // target as a proxy for checking that it always returns.
-
- // FIXME: This isn't aggressive enough; a call which only writes to a global
- // is guaranteed to return.
- return CB->onlyReadsMemory() || CB->onlyAccessesArgMemory();
+ // FIXME: Temporarily assume that all side-effect free intrinsics will
+ // return. Remove this workaround once all intrinsics are appropriately
+ // annotated.
+ return isa<IntrinsicInst>(CB) && CB->onlyReadsMemory();
}
// Other instructions return normally.
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
; IS__CGSCC____-LABEL: define {{[^@]+}}@c3
; IS__CGSCC____-SAME: (i32* nofree writeonly [[Q:%.*]]) [[ATTR1]] {
-; IS__CGSCC____-NEXT: call void @c2(i32* nofree writeonly [[Q]]) [[ATTR16:#.*]]
+; IS__CGSCC____-NEXT: call void @c2(i32* nofree writeonly [[Q]]) [[ATTR17:#.*]]
; IS__CGSCC____-NEXT: ret void
;
call void @c2(i32* %q)
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readonly willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@c7
; IS__TUNIT____-SAME: (i32* nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) [[ATTR2]] {
-; IS__TUNIT____-NEXT: [[PTR:%.*]] = call i1* @lookup_bit(i32* noalias nofree readnone [[Q]], i32 [[BITNO]]) [[ATTR14:#.*]]
+; IS__TUNIT____-NEXT: [[PTR:%.*]] = call i1* @lookup_bit(i32* noalias nofree readnone [[Q]], i32 [[BITNO]]) [[ATTR15:#.*]]
; IS__TUNIT____-NEXT: [[VAL:%.*]] = load i1, i1* [[PTR]], align 1
; IS__TUNIT____-NEXT: ret i1 [[VAL]]
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@c7
; IS__CGSCC____-SAME: (i32* nofree readonly [[Q:%.*]], i32 [[BITNO:%.*]]) [[ATTR2]] {
-; IS__CGSCC____-NEXT: [[PTR:%.*]] = call i1* @lookup_bit(i32* noalias nofree readnone [[Q]], i32 [[BITNO]]) [[ATTR17:#.*]]
+; IS__CGSCC____-NEXT: [[PTR:%.*]] = call i1* @lookup_bit(i32* noalias nofree readnone [[Q]], i32 [[BITNO]]) [[ATTR18:#.*]]
; IS__CGSCC____-NEXT: [[VAL:%.*]] = load i1, i1* [[PTR]], align 1
; IS__CGSCC____-NEXT: ret i1 [[VAL]]
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@nc2
; IS__CGSCC____-SAME: (i32* nocapture nofree [[P:%.*]], i32* nofree [[Q:%.*]]) [[ATTR5]] {
-; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i32 @nc1(i32* nofree [[Q]], i32* nocapture nofree [[P]], i1 noundef false) [[ATTR18:#.*]]
+; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i32 @nc1(i32* nofree [[Q]], i32* nocapture nofree [[P]], i1 noundef false) [[ATTR14:#.*]]
; IS__CGSCC____-NEXT: ret void
;
%1 = call i32 @nc1(i32* %q, i32* %p, i1 0) ; <i32> [#uses=0]
; IS__TUNIT____: Function Attrs: argmemonly nounwind
; IS__TUNIT____-LABEL: define {{[^@]+}}@nc4
; IS__TUNIT____-SAME: (i8* [[P:%.*]]) [[ATTR6:#.*]] {
-; IS__TUNIT____-NEXT: call void @external(i8* readonly [[P]]) [[ATTR11:#.*]]
+; IS__TUNIT____-NEXT: call void @external(i8* readonly [[P]]) [[ATTR16:#.*]]
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____: Function Attrs: argmemonly nounwind
; IS__CGSCC____-LABEL: define {{[^@]+}}@nc4
; IS__CGSCC____-SAME: (i8* [[P:%.*]]) [[ATTR6:#.*]] {
-; IS__CGSCC____-NEXT: call void @external(i8* readonly [[P]]) [[ATTR13:#.*]]
+; IS__CGSCC____-NEXT: call void @external(i8* readonly [[P]]) [[ATTR19:#.*]]
; IS__CGSCC____-NEXT: ret void
;
call void @external(i8* %p)
; IS__TUNIT____-LABEL: define {{[^@]+}}@nocaptureLaunder
; IS__TUNIT____-SAME: (i8* nocapture nofree [[P:%.*]]) [[ATTR5]] {
; IS__TUNIT____-NEXT: entry:
-; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR15:#.*]]
+; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR17:#.*]]
; IS__TUNIT____-NEXT: store i8 42, i8* [[B]], align 1
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@nocaptureLaunder
; IS__CGSCC____-SAME: (i8* nocapture nofree [[P:%.*]]) [[ATTR10:#.*]] {
; IS__CGSCC____-NEXT: entry:
-; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR17]]
+; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR18]]
; IS__CGSCC____-NEXT: store i8 42, i8* [[B]], align 1
; IS__CGSCC____-NEXT: ret void
;
; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@captureLaunder
; IS__TUNIT____-SAME: (i8* nofree [[P:%.*]]) [[ATTR5]] {
-; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR15]]
+; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR17]]
; IS__TUNIT____-NEXT: store i8* [[B]], i8** @g2, align 8
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____: Function Attrs: nofree nosync nounwind willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@captureLaunder
; IS__CGSCC____-SAME: (i8* nofree [[P:%.*]]) [[ATTR10]] {
-; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR17]]
+; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.launder.invariant.group.p0i8(i8* nofree [[P]]) [[ATTR18]]
; IS__CGSCC____-NEXT: store i8* [[B]], i8** @g2, align 8
; IS__CGSCC____-NEXT: ret void
;
; IS__TUNIT____-LABEL: define {{[^@]+}}@nocaptureStrip
; IS__TUNIT____-SAME: (i8* nocapture nofree writeonly [[P:%.*]]) [[ATTR1]] {
; IS__TUNIT____-NEXT: entry:
-; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR15]]
+; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR17]]
; IS__TUNIT____-NEXT: store i8 42, i8* [[B]], align 1
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____-LABEL: define {{[^@]+}}@nocaptureStrip
; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[P:%.*]]) [[ATTR11:#.*]] {
; IS__CGSCC____-NEXT: entry:
-; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR17]]
+; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR18]]
; IS__CGSCC____-NEXT: store i8 42, i8* [[B]], align 1
; IS__CGSCC____-NEXT: ret void
;
; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn writeonly
; IS__TUNIT____-LABEL: define {{[^@]+}}@captureStrip
; IS__TUNIT____-SAME: (i8* nofree writeonly [[P:%.*]]) [[ATTR1]] {
-; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR15]]
+; IS__TUNIT____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR17]]
; IS__TUNIT____-NEXT: store i8* [[B]], i8** @g3, align 8
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____: Function Attrs: nofree nosync nounwind willreturn writeonly
; IS__CGSCC____-LABEL: define {{[^@]+}}@captureStrip
; IS__CGSCC____-SAME: (i8* nofree writeonly [[P:%.*]]) [[ATTR11]] {
-; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR17]]
+; IS__CGSCC____-NEXT: [[B:%.*]] = call i8* @llvm.strip.invariant.group.p0i8(i8* noalias nofree readnone [[P]]) [[ATTR18]]
; IS__CGSCC____-NEXT: store i8* [[B]], i8** @g3, align 8
; IS__CGSCC____-NEXT: ret void
;
ret i8* %p
}
-declare i8* @maybe_returned_ptr(i8* readonly %ptr) readonly nounwind
-declare i8 @maybe_returned_val(i8* %ptr) readonly nounwind
-declare void @val_use(i8 %ptr) readonly nounwind
+declare i8* @maybe_returned_ptr(i8* readonly %ptr) readonly nounwind willreturn
+declare i8 @maybe_returned_val(i8* %ptr) readonly nounwind willreturn
+declare void @val_use(i8 %ptr) readonly nounwind willreturn
; FIXME: Both pointers should be nocapture
define void @ptr_uses(i8* %ptr, i8* %wptr) {
-; CHECK: Function Attrs: nounwind
+; CHECK: Function Attrs: nounwind willreturn
; CHECK-LABEL: define {{[^@]+}}@ptr_uses
-; CHECK-SAME: (i8* [[PTR:%.*]], i8* nocapture nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) [[ATTR13:#.*]] {
-; CHECK-NEXT: [[CALL_PTR:%.*]] = call i8* @maybe_returned_ptr(i8* readonly [[PTR]]) [[ATTR4]]
-; CHECK-NEXT: [[CALL_VAL:%.*]] = call i8 @maybe_returned_val(i8* readonly [[CALL_PTR]]) [[ATTR4]]
+; CHECK-SAME: (i8* [[PTR:%.*]], i8* nocapture nonnull writeonly dereferenceable(1) [[WPTR:%.*]]) [[ATTR14:#.*]] {
; CHECK-NEXT: store i8 0, i8* [[WPTR]], align 1
; CHECK-NEXT: ret void
;
; nonnull if neither can ever return null. (In this case, they
; just never return period.)
define i8* @test4_helper() {
-; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test4_helper
-; NOT_CGSCC_NPM-SAME: () [[ATTR2:#.*]] {
-; NOT_CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4()
-; NOT_CGSCC_NPM-NEXT: unreachable
-;
-; IS__CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test4_helper
-; IS__CGSCC_NPM-SAME: () [[ATTR2:#.*]] {
-; IS__CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4()
-; IS__CGSCC_NPM-NEXT: unreachable
+; CHECK: Function Attrs: nofree noreturn nosync nounwind readnone
+; CHECK-LABEL: define {{[^@]+}}@test4_helper
+; CHECK-SAME: () [[ATTR2:#.*]] {
+; CHECK-NEXT: [[RET:%.*]] = call i8* @test4() [[ATTR2]]
+; CHECK-NEXT: unreachable
;
%ret = call i8* @test4()
ret i8* %ret
}
define i8* @test4() {
-; NOT_CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
-; NOT_CGSCC_NPM-LABEL: define {{[^@]+}}@test4
-; NOT_CGSCC_NPM-SAME: () [[ATTR2]] {
-; NOT_CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4_helper()
-; NOT_CGSCC_NPM-NEXT: unreachable
-;
-; IS__CGSCC_NPM: Function Attrs: nofree noreturn nosync nounwind readnone
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@test4
-; IS__CGSCC_NPM-SAME: () [[ATTR2]] {
-; IS__CGSCC_NPM-NEXT: [[RET:%.*]] = call i8* @test4_helper()
-; IS__CGSCC_NPM-NEXT: unreachable
+; CHECK: Function Attrs: nofree noreturn nosync nounwind readnone
+; CHECK-LABEL: define {{[^@]+}}@test4
+; CHECK-SAME: () [[ATTR2]] {
+; CHECK-NEXT: [[RET:%.*]] = call i8* @test4_helper() [[ATTR2]]
+; CHECK-NEXT: unreachable
;
%ret = call i8* @test4_helper()
ret i8* %ret
declare void @use2nonnull(i8* nonnull %x, i8* nonnull %y);
declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z);
-declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantees that execution continues to successor
+declare i8 @use1safecall(i8* %x) readonly nounwind willreturn ; nounwind+willreturn guarantees that execution continues to successor
; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute.
; NOT_CGSCC_OPM: Function Attrs: nofree nounwind readonly willreturn
; NOT_CGSCC_OPM-LABEL: define {{[^@]+}}@mybasename
; NOT_CGSCC_OPM-SAME: (i8* nofree readonly [[STR:%.*]]) [[ATTR11:#.*]] {
-; NOT_CGSCC_OPM-NEXT: [[CALL:%.*]] = call i8* @strrchr(i8* nofree readonly [[STR]], i32 noundef 47) [[ATTR15:#.*]]
+; NOT_CGSCC_OPM-NEXT: [[CALL:%.*]] = call i8* @strrchr(i8* nofree readonly [[STR]], i32 noundef 47) [[ATTR14]]
; NOT_CGSCC_OPM-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[CALL]], null
; NOT_CGSCC_OPM-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 1
; NOT_CGSCC_OPM-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i8* [[ADD_PTR]], i8* [[STR]]
; IS__CGSCC_OPM: Function Attrs: nofree nounwind readonly willreturn
; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@mybasename
; IS__CGSCC_OPM-SAME: (i8* nofree readonly [[STR:%.*]]) [[ATTR12:#.*]] {
-; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i8* @strrchr(i8* nofree readonly [[STR]], i32 noundef 47) [[ATTR16:#.*]]
+; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i8* @strrchr(i8* nofree readonly [[STR]], i32 noundef 47) [[ATTR15]]
; IS__CGSCC_OPM-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[CALL]], null
; IS__CGSCC_OPM-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALL]], i64 1
; IS__CGSCC_OPM-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i8* [[ADD_PTR]], i8* [[STR]]
;
; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind
; IS__CGSCC____-LABEL: define {{[^@]+}}@external_ret2_nrw
-; IS__CGSCC____-SAME: (i32* nofree [[N0:%.*]], i32* nofree nonnull align 4 dereferenceable(4) [[R0:%.*]], i32* nofree returned [[W0:%.*]]) [[ATTR0:#.*]] {
+; IS__CGSCC____-SAME: (i32* nofree [[N0:%.*]], i32* nofree [[R0:%.*]], i32* nofree returned [[W0:%.*]]) [[ATTR0:#.*]] {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @internal_ret0_nw(i32* nofree [[N0]], i32* nofree [[W0]]) [[ATTR2:#.*]]
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree [[W0]]) [[ATTR2]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC____: if.end:
-; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]]) [[ATTR2]]
+; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree [[W0]]) [[ATTR2]]
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32, i32* [[R0]], align 4
; IS__CGSCC____-NEXT: [[TMP2:%.*]] = load i32, i32* [[R1]], align 4
; IS__CGSCC____-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP2]]
; IS__CGSCC____: if.then:
; IS__CGSCC____-NEXT: br label [[RETURN:%.*]]
; IS__CGSCC____: if.end:
-; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]]) [[ATTR2]]
+; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @internal_ret1_rrw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree [[W0]]) [[ATTR2]]
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = load i32, i32* [[R0]], align 4
; IS__CGSCC____-NEXT: store i32 [[TMP1]], i32* [[W0]], align 4
; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32* @internal_ret0_nw(i32* nofree nonnull align 4 dereferenceable(4) [[R0]], i32* nofree nonnull align 4 dereferenceable(4) [[W0]]) [[ATTR2]]
;
; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind
; IS__CGSCC____-LABEL: define {{[^@]+}}@external_source_ret2_nrw
-; IS__CGSCC____-SAME: (i32* nofree [[N0:%.*]], i32* nofree align 4 [[R0:%.*]], i32* nofree returned [[W0:%.*]]) [[ATTR0]] {
+; IS__CGSCC____-SAME: (i32* nofree [[N0:%.*]], i32* nofree [[R0:%.*]], i32* nofree returned [[W0:%.*]]) [[ATTR0]] {
; IS__CGSCC____-NEXT: entry:
-; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nocapture nofree readonly align 4 [[R0]], i32* nofree writeonly "no-capture-maybe-returned" [[W0]]) [[ATTR4:#.*]]
-; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree align 4 [[R0]], i32* nofree [[W0]]) [[ATTR3]]
+; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i32* @external_sink_ret2_nrw(i32* nofree [[N0]], i32* nocapture nofree readonly [[R0]], i32* nofree writeonly "no-capture-maybe-returned" [[W0]]) [[ATTR4:#.*]]
+; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i32* @external_ret2_nrw(i32* nofree [[N0]], i32* nofree [[R0]], i32* nofree [[W0]]) [[ATTR3]]
; IS__CGSCC____-NEXT: ret i32* [[CALL1]]
;
entry:
declare void @use2nonnull(i8* nonnull noundef %x, i8* nonnull noundef %y);
declare void @use3nonnull(i8* nonnull noundef %x, i8* nonnull noundef %y, i8* nonnull noundef %z);
-declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantees that execution continues to successor
+declare i8 @use1safecall(i8* %x) nounwind willreturn ; nounwind+willreturn guarantees that execution continues to successor
; Without noundef, nonnull cannot be propagated to the parent
declare float @convergent_func(float, float) #0
declare float @func(float, float) #1
-attributes #0 = { nounwind readnone convergent }
-attributes #1 = { nounwind readnone }
+attributes #0 = { nounwind readnone convergent willreturn }
+attributes #1 = { nounwind readnone willreturn }
declare void @useit2(float)
attributes #0 = { noinline nounwind readnone uwtable }
-attributes #1 = { nounwind readnone }
+attributes #1 = { nounwind readnone willreturn }
attributes #2 = { noinline nounwind uwtable }
!llvm.dbg.cu = !{!0}
; RUN: opt < %s -inline-threshold=0 -always-inline -S | FileCheck %s
; RUN: opt < %s -passes=always-inline -S | FileCheck %s
-declare i8* @foo(i8*) argmemonly nounwind
+declare i8* @foo(i8*) nounwind willreturn
define i8* @callee(i8 *%p) alwaysinline {
; CHECK-LABEL: @callee(
ret i8* %p
}
-declare i8* @baz(i8*) nounwind readonly
+declare i8* @baz(i8*) nounwind willreturn
define internal i8* @callee5(i8* %p) alwaysinline {
%r = call i8* @foo(i8* %p)
%v = call i8* @baz(i8* %p)
ret void
}
-declare void @dummy(i1) nounwind argmemonly
+declare void @dummy(i1) nounwind willreturn
define void @can_fold_some_use_before_assume(i32* %array) {
; CHECK-LABEL:@can_fold_some_use_before_assume
ret void
}
-declare void @dummy(i1) nounwind argmemonly
+declare void @dummy(i1) nounwind willreturn
; same as dont_fold_guard1 but there's a use immediately after guard and before
; branch. We can fold that use.
define void @dont_fold_guard2(i8* %addr, i32 %i, i32 %length) {
define internal void @.omp_outlined..5(i32* noalias %.global_tid., i32* noalias %.bound_tid., i32* dereferenceable(4) %a) {
; CHECK-LABEL: define {{[^@]+}}@.omp_outlined..5
-; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
+; CHECK-SAME: (i32* noalias nocapture readonly [[DOTGLOBAL_TID_:%.*]], i32* noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], i32* nocapture noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef nonnull [[GLOB0]]) [[ATTR12]]
; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[DOTGLOBAL_TID_]], align 4
StringRef Assembly =
"declare void @nounwind_readonly(i32*) nounwind readonly "
"declare void @nounwind_argmemonly(i32*) nounwind argmemonly "
+ "declare void @nounwind_willreturn(i32*) nounwind willreturn "
"declare void @throws_but_readonly(i32*) readonly "
"declare void @throws_but_argmemonly(i32*) argmemonly "
- "declare void @nounwind_willreturn(i32*) nounwind willreturn"
+ "declare void @throws_but_willreturn(i32*) willreturn "
" "
"declare void @unknown(i32*) "
" "
"define void @f(i32* %p) { "
" call void @nounwind_readonly(i32* %p) "
" call void @nounwind_argmemonly(i32* %p) "
+ " call void @nounwind_willreturn(i32* %p)"
" call void @throws_but_readonly(i32* %p) "
" call void @throws_but_argmemonly(i32* %p) "
+ " call void @throws_but_willreturn(i32* %p) "
" call void @unknown(i32* %p) nounwind readonly "
" call void @unknown(i32* %p) nounwind argmemonly "
+ " call void @unknown(i32* %p) nounwind willreturn "
" call void @unknown(i32* %p) readonly "
" call void @unknown(i32* %p) argmemonly "
- " call void @nounwind_willreturn(i32* %p)"
+ " call void @unknown(i32* %p) willreturn "
" ret void "
"} ";
auto &BB = F->getEntryBlock();
bool ExpectedAnswers[] = {
- true, // call void @nounwind_readonly(i32* %p)
- true, // call void @nounwind_argmemonly(i32* %p)
+ false, // call void @nounwind_readonly(i32* %p)
+ false, // call void @nounwind_argmemonly(i32* %p)
+ true, // call void @nounwind_willreturn(i32* %p)
false, // call void @throws_but_readonly(i32* %p)
false, // call void @throws_but_argmemonly(i32* %p)
- true, // call void @unknown(i32* %p) nounwind readonly
- true, // call void @unknown(i32* %p) nounwind argmemonly
+ false, // call void @throws_but_willreturn(i32* %p)
+ false, // call void @unknown(i32* %p) nounwind readonly
+ false, // call void @unknown(i32* %p) nounwind argmemonly
+ true, // call void @unknown(i32* %p) nounwind willreturn
false, // call void @unknown(i32* %p) readonly
false, // call void @unknown(i32* %p) argmemonly
- true, // call void @nounwind_willreturn(i32* %p)
+ false, // call void @unknown(i32* %p) willreturn
false, // ret void
};