[llvm-branch-commits] [llvm] 5d12b97 - [ValueTracking] Don't assume readonly function will return
Nikita Popov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Jan 24 01:46:02 PST 2021
Author: Nikita Popov
Date: 2021-01-24T10:40:21+01:00
New Revision: 5d12b976b004e5022b523d3bc368aa6794aad988
URL: https://github.com/llvm/llvm-project/commit/5d12b976b004e5022b523d3bc368aa6794aad988
DIFF: https://github.com/llvm/llvm-project/commit/5d12b976b004e5022b523d3bc368aa6794aad988.diff
LOG: [ValueTracking] Don't assume readonly function will return
This is similar to D94106, but for the
isGuaranteedToTransferExecutionToSuccessor() helper. We should not
assume that readonly functions will return, as this is only true for
mustprogress functions (in which case we already infer willreturn).
As with the DCE change, for now continue assuming that readonly
intrinsics will return, as not all target intrinsics have been
annotated yet.
Differential Revision: https://reviews.llvm.org/D95288
Added:
Modified:
llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/Attributor/nocapture-1.ll
llvm/test/Transforms/Attributor/nonnull.ll
llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
llvm/test/Transforms/FunctionAttrs/nonnull.ll
llvm/test/Transforms/GVNHoist/hoist-convergent.ll
llvm/test/Transforms/GVNHoist/hoist-pr31891.ll
llvm/test/Transforms/Inline/ret_attr_update.ll
llvm/test/Transforms/JumpThreading/assume.ll
llvm/test/Transforms/JumpThreading/guards.ll
llvm/test/Transforms/OpenMP/parallel_deletion.ll
llvm/unittests/Analysis/ValueTrackingTest.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 672497d8cac7..5600a3b33750 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5040,23 +5040,10 @@ bool llvm::isGuaranteedToTransferExecutionToSuccessor(const Instruction *I) {
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.
diff --git a/llvm/test/Transforms/Attributor/nocapture-1.ll b/llvm/test/Transforms/Attributor/nocapture-1.ll
index 74b39d718501..1124c651615a 100644
--- a/llvm/test/Transforms/Attributor/nocapture-1.ll
+++ b/llvm/test/Transforms/Attributor/nocapture-1.ll
@@ -48,7 +48,7 @@ define void @c3(i32* %q) {
; 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)
@@ -215,14 +215,14 @@ define i1 @c7(i32* %q, i32 %bitno) {
; 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]]
;
@@ -330,7 +330,7 @@ define void @nc2(i32* %p, i32* %q) {
; 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]
@@ -355,13 +355,13 @@ define void @nc4(i8* %p) {
; 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)
@@ -609,7 +609,7 @@ define void @nocaptureLaunder(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
;
@@ -617,7 +617,7 @@ define void @nocaptureLaunder(i8* %p) {
; 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
;
@@ -632,14 +632,14 @@ define void @captureLaunder(i8* %p) {
; 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
;
@@ -653,7 +653,7 @@ define void @nocaptureStrip(i8* %p) {
; 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
;
@@ -661,7 +661,7 @@ define void @nocaptureStrip(i8* %p) {
; 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
;
@@ -676,14 +676,14 @@ define void @captureStrip(i8* %p) {
; 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
;
@@ -840,17 +840,15 @@ entry:
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
;
diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll
index b54ab775d53a..f5062eb4c731 100644
--- a/llvm/test/Transforms/Attributor/nonnull.ll
+++ b/llvm/test/Transforms/Attributor/nonnull.ll
@@ -146,34 +146,22 @@ define i8* @test3(i1 %c) {
; 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
@@ -802,7 +790,7 @@ declare void @use1nonnull(i8* nonnull %x);
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.
@@ -1524,7 +1512,7 @@ define i8* @mybasename(i8* nofree readonly %str) {
; 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]]
@@ -1533,7 +1521,7 @@ define i8* @mybasename(i8* nofree readonly %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]]
diff --git a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
index 32c597010b88..f444dacadc3c 100644
--- a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
+++ b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
@@ -47,7 +47,7 @@ define i32* @external_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
;
; 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]]
@@ -179,7 +179,7 @@ define internal i32* @internal_ret1_rrw(i32* %r0, i32* %r1, i32* %w0) {
; 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]]
@@ -306,7 +306,7 @@ define internal i32* @internal_ret1_rw(i32* %r0, i32* %w0) {
; 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]]
@@ -352,10 +352,10 @@ define i32* @external_source_ret2_nrw(i32* %n0, i32* %r0, i32* %w0) {
;
; 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:
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
index 56457b33d1c6..ae5245e4735b 100644
--- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
@@ -332,7 +332,7 @@ declare void @use1nonnull_without_noundef(i8* nonnull %x);
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
diff --git a/llvm/test/Transforms/GVNHoist/hoist-convergent.ll b/llvm/test/Transforms/GVNHoist/hoist-convergent.ll
index 73d923c9014b..f5bf03f39b58 100644
--- a/llvm/test/Transforms/GVNHoist/hoist-convergent.ll
+++ b/llvm/test/Transforms/GVNHoist/hoist-convergent.ll
@@ -89,5 +89,5 @@ if.end:
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 }
diff --git a/llvm/test/Transforms/GVNHoist/hoist-pr31891.ll b/llvm/test/Transforms/GVNHoist/hoist-pr31891.ll
index 0c667d71468d..380c197a60fd 100644
--- a/llvm/test/Transforms/GVNHoist/hoist-pr31891.ll
+++ b/llvm/test/Transforms/GVNHoist/hoist-pr31891.ll
@@ -52,7 +52,7 @@ declare void @useit1(float)
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}
diff --git a/llvm/test/Transforms/Inline/ret_attr_update.ll b/llvm/test/Transforms/Inline/ret_attr_update.ll
index 647029e13459..bb10920ebf0e 100644
--- a/llvm/test/Transforms/Inline/ret_attr_update.ll
+++ b/llvm/test/Transforms/Inline/ret_attr_update.ll
@@ -2,7 +2,7 @@
; 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(
@@ -120,7 +120,7 @@ define i8* @test4(i8* %ptr, i64 %x) {
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)
diff --git a/llvm/test/Transforms/JumpThreading/assume.ll b/llvm/test/Transforms/JumpThreading/assume.ll
index f58ee299cba0..08775b01d750 100644
--- a/llvm/test/Transforms/JumpThreading/assume.ll
+++ b/llvm/test/Transforms/JumpThreading/assume.ll
@@ -100,7 +100,7 @@ error:
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
diff --git a/llvm/test/Transforms/JumpThreading/guards.ll b/llvm/test/Transforms/JumpThreading/guards.ll
index c760283f9e52..911eec8dad27 100644
--- a/llvm/test/Transforms/JumpThreading/guards.ll
+++ b/llvm/test/Transforms/JumpThreading/guards.ll
@@ -206,7 +206,7 @@ BB2:
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) {
diff --git a/llvm/test/Transforms/OpenMP/parallel_deletion.ll b/llvm/test/Transforms/OpenMP/parallel_deletion.ll
index 1a6d1587a8c8..76c63172619f 100644
--- a/llvm/test/Transforms/OpenMP/parallel_deletion.ll
+++ b/llvm/test/Transforms/OpenMP/parallel_deletion.ll
@@ -286,7 +286,7 @@ declare void @__kmpc_end_master(%struct.ident_t*, i32)
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
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index f3240e0b4ff4..18fb1545a945 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -614,22 +614,26 @@ TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) {
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 "
"} ";
@@ -643,15 +647,18 @@ TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) {
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
};
More information about the llvm-branch-commits
mailing list