Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -5040,23 +5040,10 @@ 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(CB) && CB->onlyReadsMemory(); } // Other instructions return normally. Index: test/Transforms/Attributor/nocapture-1.ll =================================================================== --- test/Transforms/Attributor/nocapture-1.ll +++ test/Transforms/Attributor/nocapture-1.ll @@ -48,7 +48,7 @@ ; 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 @@ ; 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 @@ ; 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) ; [#uses=0] @@ -355,13 +355,13 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ 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 ; Index: test/Transforms/Attributor/nonnull.ll =================================================================== --- test/Transforms/Attributor/nonnull.ll +++ test/Transforms/Attributor/nonnull.ll @@ -146,34 +146,22 @@ ; 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 @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 @@ ; 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 @@ ; 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]] Index: test/Transforms/Attributor/read_write_returned_arguments_scc.ll =================================================================== --- test/Transforms/Attributor/read_write_returned_arguments_scc.ll +++ test/Transforms/Attributor/read_write_returned_arguments_scc.ll @@ -47,7 +47,7 @@ ; ; 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 @@ ; 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 @@ ; 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 @@ ; ; 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: Index: test/Transforms/FunctionAttrs/nonnull.ll =================================================================== --- test/Transforms/FunctionAttrs/nonnull.ll +++ test/Transforms/FunctionAttrs/nonnull.ll @@ -332,7 +332,7 @@ 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 Index: test/Transforms/GVNHoist/hoist-convergent.ll =================================================================== --- test/Transforms/GVNHoist/hoist-convergent.ll +++ test/Transforms/GVNHoist/hoist-convergent.ll @@ -89,5 +89,5 @@ 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 } Index: test/Transforms/GVNHoist/hoist-pr31891.ll =================================================================== --- test/Transforms/GVNHoist/hoist-pr31891.ll +++ test/Transforms/GVNHoist/hoist-pr31891.ll @@ -52,7 +52,7 @@ 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} Index: test/Transforms/Inline/ret_attr_update.ll =================================================================== --- test/Transforms/Inline/ret_attr_update.ll +++ 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 @@ 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) Index: test/Transforms/JumpThreading/assume.ll =================================================================== --- test/Transforms/JumpThreading/assume.ll +++ test/Transforms/JumpThreading/assume.ll @@ -100,7 +100,7 @@ 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 Index: test/Transforms/JumpThreading/guards.ll =================================================================== --- test/Transforms/JumpThreading/guards.ll +++ test/Transforms/JumpThreading/guards.ll @@ -206,7 +206,7 @@ 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) { Index: test/Transforms/OpenMP/parallel_deletion.ll =================================================================== --- test/Transforms/OpenMP/parallel_deletion.ll +++ test/Transforms/OpenMP/parallel_deletion.ll @@ -286,7 +286,7 @@ 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 Index: unittests/Analysis/ValueTrackingTest.cpp =================================================================== --- unittests/Analysis/ValueTrackingTest.cpp +++ unittests/Analysis/ValueTrackingTest.cpp @@ -643,12 +643,12 @@ 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) 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 @unknown(i32* %p) nounwind readonly + false, // call void @unknown(i32* %p) nounwind argmemonly false, // call void @unknown(i32* %p) readonly false, // call void @unknown(i32* %p) argmemonly true, // call void @nounwind_willreturn(i32* %p)