diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h index d77d5cabfda5..40fdfc24f388 100644 --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -142,6 +142,12 @@ namespace AA { /// instruction/argument of \p Scope. bool isValidInScope(const Value &V, const Function *Scope); +/// Return true if \p V is a valid value at position \p CtxI, that is a +/// constant, an argument of the same function as \p CtxI, or an instruction in +/// that function that dominates \p CtxI. +bool isValidAtPosition(const Value &V, const Instruction &CtxI, + InformationCache &InfoCache); + /// Try to convert \p V to type \p Ty without introducing new instructions. If /// this is not possible return `nullptr`. Note: this function basically knows /// how to cast various constants. diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 16dbb86f1c8a..e831f293bfbd 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -176,6 +176,22 @@ bool AA::isValidInScope(const Value &V, const Function *Scope) { return false; } +bool AA::isValidAtPosition(const Value &V, const Instruction &CtxI, + InformationCache &InfoCache) { + if (isa(V)) + return true; + const Function *Scope = CtxI.getFunction(); + if (auto *A = dyn_cast(&V)) + return A->getParent() == Scope; + if (auto *I = dyn_cast(&V)) + if (I->getFunction() == Scope) { + const DominatorTree *DT = + InfoCache.getAnalysisResultForFunction(*Scope); + return DT && DT->dominates(I, &CtxI); + } + return false; +} + Value *AA::getWithType(Value &V, Type &Ty) { if (V.getType() == &Ty) return &V; diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index d5f9dde104ed..0c4fe13d1023 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -4405,7 +4405,7 @@ struct AAValueSimplifyImpl : AAValueSimplify { /// Return a value we can use as replacement for the associated one, or /// nullptr if we don't have one that makes sense. - virtual Value *getReplacementValue() const { + Value *getReplacementValue(Attributor &A) const { Value *NewV; NewV = SimplifiedAssociatedValue.hasValue() ? SimplifiedAssociatedValue.getValue() @@ -4413,8 +4413,12 @@ struct AAValueSimplifyImpl : AAValueSimplify { if (!NewV) return nullptr; NewV = AA::getWithType(*NewV, *getAssociatedType()); - if (!NewV || NewV == &getAssociatedValue() || - !AA::isValidInScope(*NewV, getAnchorScope())) + if (!NewV || NewV == &getAssociatedValue()) + return nullptr; + const Instruction *CtxI = getCtxI(); + if (CtxI && !AA::isValidAtPosition(*NewV, *CtxI, A.getInfoCache())) + return nullptr; + if (!CtxI && !AA::isValidInScope(*NewV, getAnchorScope())) return nullptr; return NewV; } @@ -4469,7 +4473,7 @@ struct AAValueSimplifyImpl : AAValueSimplify { if (getAssociatedValue().user_empty()) return Changed; - if (auto *NewV = getReplacementValue()) { + if (auto *NewV = getReplacementValue(A)) { LLVM_DEBUG(dbgs() << "[ValueSimplify] " << getAssociatedValue() << " -> " << *NewV << " :: " << *this << "\n"); if (A.changeValueAfterManifest(getAssociatedValue(), *NewV)) @@ -4616,7 +4620,7 @@ struct AAValueSimplifyReturned : AAValueSimplifyImpl { ChangeStatus manifest(Attributor &A) override { ChangeStatus Changed = ChangeStatus::UNCHANGED; - if (auto *NewV = getReplacementValue()) { + if (auto *NewV = getReplacementValue(A)) { auto PredForReturned = [&](Value &, const SmallSetVector &RetInsts) { for (ReturnInst *RI : RetInsts) { @@ -4841,7 +4845,7 @@ struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating { ChangeStatus manifest(Attributor &A) override { ChangeStatus Changed = ChangeStatus::UNCHANGED; - if (auto *NewV = getReplacementValue()) { + if (auto *NewV = getReplacementValue(A)) { Use &U = cast(&getAnchorValue()) ->getArgOperandUse(getCallSiteArgNo()); if (A.changeUseAfterManifest(U, *NewV)) diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll index 824f01ff5589..a5765ed3e9d7 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll @@ -32,21 +32,39 @@ entry: define i64 @fn2b(i32 %arg) { ; -; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn -; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2b -; IS__TUNIT____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] { -; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64 -; IS__TUNIT____-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] -; IS__TUNIT____-NEXT: ret i64 [[DIV]] +; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn2b +; IS__TUNIT_OPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] { +; IS__TUNIT_OPM-NEXT: entry: +; IS__TUNIT_OPM-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64 +; IS__TUNIT_OPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] +; IS__TUNIT_OPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]]) #[[ATTR0]] +; IS__TUNIT_OPM-NEXT: ret i64 [[CALL2]] ; -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2b -; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] { -; IS__CGSCC____-NEXT: entry: -; IS__CGSCC____-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64 -; IS__CGSCC____-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] -; IS__CGSCC____-NEXT: ret i64 [[DIV]] +; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn2b +; IS__TUNIT_NPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] { +; IS__TUNIT_NPM-NEXT: entry: +; IS__TUNIT_NPM-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64 +; IS__TUNIT_NPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] +; IS__TUNIT_NPM-NEXT: ret i64 [[DIV]] +; +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2b +; IS__CGSCC_OPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] { +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64 +; IS__CGSCC_OPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] +; IS__CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]]) #[[ATTR1:[0-9]+]] +; IS__CGSCC_OPM-NEXT: ret i64 [[CALL2]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2b +; IS__CGSCC_NPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] { +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64 +; IS__CGSCC_NPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]] +; IS__CGSCC_NPM-NEXT: ret i64 [[DIV]] ; entry: %conv = sext i32 %arg to i64 @@ -83,11 +101,23 @@ entry: } define internal i64 @fn1(i64 %p1) { -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@fn1 -; IS__CGSCC____-SAME: (i64 [[P1:%.*]]) #[[ATTR0]] { -; IS__CGSCC____-NEXT: entry: -; IS__CGSCC____-NEXT: ret i64 undef +; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn1 +; IS__TUNIT_OPM-SAME: (i64 returned [[P1:%.*]]) #[[ATTR0]] { +; IS__TUNIT_OPM-NEXT: entry: +; IS__TUNIT_OPM-NEXT: ret i64 [[P1]] +; +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn1 +; IS__CGSCC_OPM-SAME: (i64 returned [[P1:%.*]]) #[[ATTR0]] { +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: ret i64 [[P1]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn1 +; IS__CGSCC_NPM-SAME: (i64 [[P1:%.*]]) #[[ATTR0]] { +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: ret i64 undef ; entry: %tobool = icmp ne i64 %p1, 0 @@ -97,5 +127,8 @@ entry: ;. ; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn } ;. -; IS__CGSCC____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } +; IS__CGSCC_OPM: attributes #[[ATTR1]] = { readnone willreturn } +;. +; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll index f1d3dce74acb..0a96ff4852df 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll @@ -8,35 +8,67 @@ target triple = "x86_64-unknown-linux-gnu" define void @fn2(i32* %P, i1 %C) { ; -; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind -; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2 -; IS__TUNIT____-SAME: (i32* nocapture nofree [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { -; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: br label [[IF_END:%.*]] -; IS__TUNIT____: for.cond1: -; IS__TUNIT____-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] -; IS__TUNIT____: if.end: -; IS__TUNIT____-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] -; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4 -; IS__TUNIT____-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 -; IS__TUNIT____-NEXT: br label [[FOR_COND1]] -; IS__TUNIT____: exit: -; IS__TUNIT____-NEXT: ret void +; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn2 +; IS__TUNIT_OPM-SAME: (i32* nocapture nofree [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { +; IS__TUNIT_OPM-NEXT: entry: +; IS__TUNIT_OPM-NEXT: br label [[IF_END:%.*]] +; IS__TUNIT_OPM: for.cond1: +; IS__TUNIT_OPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__TUNIT_OPM: if.end: +; IS__TUNIT_OPM-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4 +; IS__TUNIT_OPM-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]]) #[[ATTR3:[0-9]+]] +; IS__TUNIT_OPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4 +; IS__TUNIT_OPM-NEXT: br label [[FOR_COND1]] +; IS__TUNIT_OPM: exit: +; IS__TUNIT_OPM-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind -; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2 -; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { -; IS__CGSCC____-NEXT: entry: -; IS__CGSCC____-NEXT: br label [[IF_END:%.*]] -; IS__CGSCC____: for.cond1: -; IS__CGSCC____-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] -; IS__CGSCC____: if.end: -; IS__CGSCC____-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] -; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4 -; IS__CGSCC____-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 -; IS__CGSCC____-NEXT: br label [[FOR_COND1]] -; IS__CGSCC____: exit: -; IS__CGSCC____-NEXT: ret void +; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn2 +; IS__TUNIT_NPM-SAME: (i32* nocapture nofree [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { +; IS__TUNIT_NPM-NEXT: entry: +; IS__TUNIT_NPM-NEXT: br label [[IF_END:%.*]] +; IS__TUNIT_NPM: for.cond1: +; IS__TUNIT_NPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__TUNIT_NPM: if.end: +; IS__TUNIT_NPM-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4 +; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 +; IS__TUNIT_NPM-NEXT: br label [[FOR_COND1]] +; IS__TUNIT_NPM: exit: +; IS__TUNIT_NPM-NEXT: ret void +; +; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2 +; IS__CGSCC_OPM-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: br label [[IF_END:%.*]] +; IS__CGSCC_OPM: for.cond1: +; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__CGSCC_OPM: if.end: +; IS__CGSCC_OPM-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4 +; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]]) +; IS__CGSCC_OPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4 +; IS__CGSCC_OPM-NEXT: br label [[FOR_COND1]] +; IS__CGSCC_OPM: exit: +; IS__CGSCC_OPM-NEXT: ret void +; +; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2 +; IS__CGSCC_NPM-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: br label [[IF_END:%.*]] +; IS__CGSCC_NPM: for.cond1: +; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__CGSCC_NPM: if.end: +; IS__CGSCC_NPM-NEXT: [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4 +; IS__CGSCC_NPM-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 +; IS__CGSCC_NPM-NEXT: br label [[FOR_COND1]] +; IS__CGSCC_NPM: exit: +; IS__CGSCC_NPM-NEXT: ret void ; entry: br label %if.end @@ -55,11 +87,23 @@ exit: } define internal i32 @fn1(i32 %p1) { -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@fn1 -; IS__CGSCC____-SAME: (i32 [[P1:%.*]]) #[[ATTR1:[0-9]+]] { -; IS__CGSCC____-NEXT: entry: -; IS__CGSCC____-NEXT: ret i32 undef +; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn1 +; IS__TUNIT_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1:[0-9]+]] { +; IS__TUNIT_OPM-NEXT: entry: +; IS__TUNIT_OPM-NEXT: ret i32 [[P1]] +; +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn1 +; IS__CGSCC_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1:[0-9]+]] { +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: ret i32 [[P1]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn1 +; IS__CGSCC_NPM-SAME: (i32 [[P1:%.*]]) #[[ATTR1:[0-9]+]] { +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: ret i32 undef ; entry: %tobool = icmp ne i32 %p1, 0 @@ -69,35 +113,67 @@ entry: define void @fn_no_null_opt(i32* %P, i1 %C) null_pointer_is_valid { ; -; IS__TUNIT____: Function Attrs: nofree nosync nounwind null_pointer_is_valid -; IS__TUNIT____-LABEL: define {{[^@]+}}@fn_no_null_opt -; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]]) #[[ATTR1:[0-9]+]] { -; IS__TUNIT____-NEXT: entry: -; IS__TUNIT____-NEXT: br label [[IF_END:%.*]] -; IS__TUNIT____: for.cond1: -; IS__TUNIT____-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] -; IS__TUNIT____: if.end: -; IS__TUNIT____-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] -; IS__TUNIT____-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4 -; IS__TUNIT____-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 -; IS__TUNIT____-NEXT: br label [[FOR_COND1]] -; IS__TUNIT____: exit: -; IS__TUNIT____-NEXT: ret void +; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind null_pointer_is_valid +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn_no_null_opt +; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] { +; IS__TUNIT_OPM-NEXT: entry: +; IS__TUNIT_OPM-NEXT: br label [[IF_END:%.*]] +; IS__TUNIT_OPM: for.cond1: +; IS__TUNIT_OPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__TUNIT_OPM: if.end: +; IS__TUNIT_OPM-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__TUNIT_OPM-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4 +; IS__TUNIT_OPM-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]]) #[[ATTR3]] +; IS__TUNIT_OPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4 +; IS__TUNIT_OPM-NEXT: br label [[FOR_COND1]] +; IS__TUNIT_OPM: exit: +; IS__TUNIT_OPM-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind null_pointer_is_valid -; IS__CGSCC____-LABEL: define {{[^@]+}}@fn_no_null_opt -; IS__CGSCC____-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] { -; IS__CGSCC____-NEXT: entry: -; IS__CGSCC____-NEXT: br label [[IF_END:%.*]] -; IS__CGSCC____: for.cond1: -; IS__CGSCC____-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] -; IS__CGSCC____: if.end: -; IS__CGSCC____-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] -; IS__CGSCC____-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4 -; IS__CGSCC____-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 -; IS__CGSCC____-NEXT: br label [[FOR_COND1]] -; IS__CGSCC____: exit: -; IS__CGSCC____-NEXT: ret void +; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind null_pointer_is_valid +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn_no_null_opt +; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]]) #[[ATTR1:[0-9]+]] { +; IS__TUNIT_NPM-NEXT: entry: +; IS__TUNIT_NPM-NEXT: br label [[IF_END:%.*]] +; IS__TUNIT_NPM: for.cond1: +; IS__TUNIT_NPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__TUNIT_NPM: if.end: +; IS__TUNIT_NPM-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__TUNIT_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4 +; IS__TUNIT_NPM-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 +; IS__TUNIT_NPM-NEXT: br label [[FOR_COND1]] +; IS__TUNIT_NPM: exit: +; IS__TUNIT_NPM-NEXT: ret void +; +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind null_pointer_is_valid +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn_no_null_opt +; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] { +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: br label [[IF_END:%.*]] +; IS__CGSCC_OPM: for.cond1: +; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__CGSCC_OPM: if.end: +; IS__CGSCC_OPM-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__CGSCC_OPM-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4 +; IS__CGSCC_OPM-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]]) +; IS__CGSCC_OPM-NEXT: store i32 [[CALL]], i32* [[P]], align 4 +; IS__CGSCC_OPM-NEXT: br label [[FOR_COND1]] +; IS__CGSCC_OPM: exit: +; IS__CGSCC_OPM-NEXT: ret void +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind null_pointer_is_valid +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn_no_null_opt +; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] { +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: br label [[IF_END:%.*]] +; IS__CGSCC_NPM: for.cond1: +; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] +; IS__CGSCC_NPM: if.end: +; IS__CGSCC_NPM-NEXT: [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] +; IS__CGSCC_NPM-NEXT: [[TMP0:%.*]] = load i32, i32* null, align 4 +; IS__CGSCC_NPM-NEXT: store i32 [[TMP0]], i32* [[P]], align 4 +; IS__CGSCC_NPM-NEXT: br label [[FOR_COND1]] +; IS__CGSCC_NPM: exit: +; IS__CGSCC_NPM-NEXT: ret void ; entry: br label %if.end @@ -116,11 +192,23 @@ exit: } define internal i32 @fn0(i32 %p1) { -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@fn0 -; IS__CGSCC____-SAME: (i32 [[P1:%.*]]) #[[ATTR1]] { -; IS__CGSCC____-NEXT: entry: -; IS__CGSCC____-NEXT: ret i32 undef +; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn0 +; IS__TUNIT_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1]] { +; IS__TUNIT_OPM-NEXT: entry: +; IS__TUNIT_OPM-NEXT: ret i32 [[P1]] +; +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn0 +; IS__CGSCC_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1]] { +; IS__CGSCC_OPM-NEXT: entry: +; IS__CGSCC_OPM-NEXT: ret i32 [[P1]] +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn0 +; IS__CGSCC_NPM-SAME: (i32 [[P1:%.*]]) #[[ATTR1]] { +; IS__CGSCC_NPM-NEXT: entry: +; IS__CGSCC_NPM-NEXT: ret i32 undef ; entry: %tobool = icmp ne i32 %p1, 0 @@ -128,10 +216,15 @@ entry: ret i32 %cond } ;. -; IS__TUNIT____: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind } -; IS__TUNIT____: attributes #[[ATTR1]] = { nofree nosync nounwind null_pointer_is_valid } +; IS__TUNIT_OPM: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind } +; IS__TUNIT_OPM: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn } +; IS__TUNIT_OPM: attributes #[[ATTR2]] = { nofree nosync nounwind null_pointer_is_valid } +; IS__TUNIT_OPM: attributes #[[ATTR3]] = { nofree nosync nounwind readnone } ;. -; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind } -; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind null_pointer_is_valid } +; IS__TUNIT_NPM: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind } +; IS__TUNIT_NPM: attributes #[[ATTR1]] = { nofree nosync nounwind null_pointer_is_valid } +;. +; IS__CGSCC____: attributes #[[ATTR0:[0-9]+]] = { argmemonly nofree norecurse nosync nounwind } +; IS__CGSCC____: attributes #[[ATTR1:[0-9]+]] = { nofree norecurse nosync nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { nofree norecurse nosync nounwind null_pointer_is_valid } ;. diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll index c81fd9ed5940..d59605ef299f 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll @@ -20,19 +20,33 @@ define internal i32* @incdec(i1 %C, i32* %V) { ; IS__TUNIT____-NEXT: store i32 [[X2]], i32* [[V]], align 4 ; IS__TUNIT____-NEXT: ret i32* [[V]] ; -; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@incdec -; IS__CGSCC____-SAME: (i1 [[C:%.*]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]]) #[[ATTR0:[0-9]+]] { -; IS__CGSCC____-NEXT: [[X:%.*]] = load i32, i32* [[V]], align 4 -; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] -; IS__CGSCC____: T: -; IS__CGSCC____-NEXT: [[X1:%.*]] = add i32 [[X]], 1 -; IS__CGSCC____-NEXT: store i32 [[X1]], i32* [[V]], align 4 -; IS__CGSCC____-NEXT: ret i32* undef -; IS__CGSCC____: F: -; IS__CGSCC____-NEXT: [[X2:%.*]] = sub i32 [[X]], 1 -; IS__CGSCC____-NEXT: store i32 [[X2]], i32* [[V]], align 4 -; IS__CGSCC____-NEXT: ret i32* undef +; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@incdec +; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]], i32* noalias nofree noundef nonnull returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]]) #[[ATTR0:[0-9]+]] { +; IS__CGSCC_OPM-NEXT: [[X:%.*]] = load i32, i32* [[V]], align 4 +; IS__CGSCC_OPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; IS__CGSCC_OPM: T: +; IS__CGSCC_OPM-NEXT: [[X1:%.*]] = add i32 [[X]], 1 +; IS__CGSCC_OPM-NEXT: store i32 [[X1]], i32* [[V]], align 4 +; IS__CGSCC_OPM-NEXT: ret i32* [[V]] +; IS__CGSCC_OPM: F: +; IS__CGSCC_OPM-NEXT: [[X2:%.*]] = sub i32 [[X]], 1 +; IS__CGSCC_OPM-NEXT: store i32 [[X2]], i32* [[V]], align 4 +; IS__CGSCC_OPM-NEXT: ret i32* [[V]] +; +; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@incdec +; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]]) #[[ATTR0:[0-9]+]] { +; IS__CGSCC_NPM-NEXT: [[X:%.*]] = load i32, i32* [[V]], align 4 +; IS__CGSCC_NPM-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; IS__CGSCC_NPM: T: +; IS__CGSCC_NPM-NEXT: [[X1:%.*]] = add i32 [[X]], 1 +; IS__CGSCC_NPM-NEXT: store i32 [[X1]], i32* [[V]], align 4 +; IS__CGSCC_NPM-NEXT: ret i32* undef +; IS__CGSCC_NPM: F: +; IS__CGSCC_NPM-NEXT: [[X2:%.*]] = sub i32 [[X]], 1 +; IS__CGSCC_NPM-NEXT: store i32 [[X2]], i32* [[V]], align 4 +; IS__CGSCC_NPM-NEXT: ret i32* undef ; %X = load i32, i32* %V br i1 %C, label %T, label %F @@ -74,43 +88,81 @@ define internal { i32, i32 } @foo(i32 %A, i32 %B) { } define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 { -; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn -; IS__TUNIT____-LABEL: define {{[^@]+}}@caller -; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 { -; IS__TUNIT____-NEXT: [[Q:%.*]] = alloca i32, align 4 -; IS__TUNIT____-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]] -; IS__TUNIT____-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]] -; IS__TUNIT____-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 -; IS__TUNIT____-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]] -; IS__TUNIT____-NEXT: br label [[OK:%.*]] -; IS__TUNIT____: OK: -; IS__TUNIT____-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 -; IS__TUNIT____-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] -; IS__TUNIT____-NEXT: store i32 [[Z]], i32* [[Q]], align 4 -; IS__TUNIT____-NEXT: br label [[RET:%.*]] -; IS__TUNIT____: LPAD: -; IS__TUNIT____-NEXT: unreachable -; IS__TUNIT____: RET: -; IS__TUNIT____-NEXT: ret void +; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind willreturn +; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@caller +; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 { +; IS__TUNIT_OPM-NEXT: [[Q:%.*]] = alloca i32, align 4 +; IS__TUNIT_OPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]] +; IS__TUNIT_OPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]] +; IS__TUNIT_OPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 +; IS__TUNIT_OPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]] +; IS__TUNIT_OPM-NEXT: br label [[OK:%.*]] +; IS__TUNIT_OPM: OK: +; IS__TUNIT_OPM-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 +; IS__TUNIT_OPM-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] +; IS__TUNIT_OPM-NEXT: store i32 [[Z]], i32* [[W]], align 4 +; IS__TUNIT_OPM-NEXT: br label [[RET:%.*]] +; IS__TUNIT_OPM: LPAD: +; IS__TUNIT_OPM-NEXT: unreachable +; IS__TUNIT_OPM: RET: +; IS__TUNIT_OPM-NEXT: ret void ; -; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn -; IS__CGSCC____-LABEL: define {{[^@]+}}@caller -; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 { -; IS__CGSCC____-NEXT: [[Q:%.*]] = alloca i32, align 4 -; IS__CGSCC____-NEXT: [[W:%.*]] = call i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] -; IS__CGSCC____-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]] -; IS__CGSCC____-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 -; IS__CGSCC____-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]] -; IS__CGSCC____-NEXT: br label [[OK:%.*]] -; IS__CGSCC____: OK: -; IS__CGSCC____-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 -; IS__CGSCC____-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] -; IS__CGSCC____-NEXT: store i32 [[Z]], i32* [[Q]], align 4 -; IS__CGSCC____-NEXT: br label [[RET:%.*]] -; IS__CGSCC____: LPAD: -; IS__CGSCC____-NEXT: unreachable -; IS__CGSCC____: RET: -; IS__CGSCC____-NEXT: ret void +; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind willreturn +; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@caller +; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 { +; IS__TUNIT_NPM-NEXT: [[Q:%.*]] = alloca i32, align 4 +; IS__TUNIT_NPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]] +; IS__TUNIT_NPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]] +; IS__TUNIT_NPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 +; IS__TUNIT_NPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]] +; IS__TUNIT_NPM-NEXT: br label [[OK:%.*]] +; IS__TUNIT_NPM: OK: +; IS__TUNIT_NPM-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 +; IS__TUNIT_NPM-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] +; IS__TUNIT_NPM-NEXT: store i32 [[Z]], i32* [[Q]], align 4 +; IS__TUNIT_NPM-NEXT: br label [[RET:%.*]] +; IS__TUNIT_NPM: LPAD: +; IS__TUNIT_NPM-NEXT: unreachable +; IS__TUNIT_NPM: RET: +; IS__TUNIT_NPM-NEXT: ret void +; +; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@caller +; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 { +; IS__CGSCC_OPM-NEXT: [[Q:%.*]] = alloca i32, align 4 +; IS__CGSCC_OPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] +; IS__CGSCC_OPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]] +; IS__CGSCC_OPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 +; IS__CGSCC_OPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]] +; IS__CGSCC_OPM-NEXT: br label [[OK:%.*]] +; IS__CGSCC_OPM: OK: +; IS__CGSCC_OPM-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 +; IS__CGSCC_OPM-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] +; IS__CGSCC_OPM-NEXT: store i32 [[Z]], i32* [[W]], align 4 +; IS__CGSCC_OPM-NEXT: br label [[RET:%.*]] +; IS__CGSCC_OPM: LPAD: +; IS__CGSCC_OPM-NEXT: unreachable +; IS__CGSCC_OPM: RET: +; IS__CGSCC_OPM-NEXT: ret void +; +; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@caller +; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 { +; IS__CGSCC_NPM-NEXT: [[Q:%.*]] = alloca i32, align 4 +; IS__CGSCC_NPM-NEXT: [[W:%.*]] = call i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] +; IS__CGSCC_NPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]] +; IS__CGSCC_NPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 +; IS__CGSCC_NPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]] +; IS__CGSCC_NPM-NEXT: br label [[OK:%.*]] +; IS__CGSCC_NPM: OK: +; IS__CGSCC_NPM-NEXT: [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0 +; IS__CGSCC_NPM-NEXT: [[Z:%.*]] = add i32 [[X1]], [[X2]] +; IS__CGSCC_NPM-NEXT: store i32 [[Z]], i32* [[Q]], align 4 +; IS__CGSCC_NPM-NEXT: br label [[RET:%.*]] +; IS__CGSCC_NPM: LPAD: +; IS__CGSCC_NPM-NEXT: unreachable +; IS__CGSCC_NPM: RET: +; IS__CGSCC_NPM-NEXT: ret void ; %Q = alloca i32 ;; Call incdec to see if %W is properly replaced by %Q @@ -142,11 +194,11 @@ declare i32 @__gxx_personality_v0(...) ;. ; IS__TUNIT____: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind willreturn } ; IS__TUNIT____: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn } -; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn } +; IS__TUNIT____: attributes #[[ATTR2:[0-9]+]] = { nofree nosync nounwind willreturn } ;. -; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR0:[0-9]+]] = { argmemonly nofree norecurse nosync nounwind willreturn } ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR2]] = { nounwind willreturn } -; IS__CGSCC____: attributes #[[ATTR3]] = { readnone willreturn } -; IS__CGSCC____: attributes #[[ATTR4]] = { nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { nounwind willreturn } +; IS__CGSCC____: attributes #[[ATTR3:[0-9]+]] = { readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { nounwind readnone willreturn } ;. diff --git a/llvm/test/Transforms/Attributor/heap_to_stack.ll b/llvm/test/Transforms/Attributor/heap_to_stack.ll index 50b8463f8df1..fb4c841ada29 100644 --- a/llvm/test/Transforms/Attributor/heap_to_stack.ll +++ b/llvm/test/Transforms/Attributor/heap_to_stack.ll @@ -41,9 +41,11 @@ define void @h2s_value_simplify_interaction(i1 %c, i8* %A) { ; IS________OPM: f: ; IS________OPM-NEXT: br label [[J:%.*]] ; IS________OPM: f2: -; IS________OPM-NEXT: [[L:%.*]] = load i8, i8* [[M]], align 1 +; IS________OPM-NEXT: [[C1:%.*]] = bitcast i8* [[M]] to i32* +; IS________OPM-NEXT: [[C2:%.*]] = bitcast i32* [[C1]] to i8* +; IS________OPM-NEXT: [[L:%.*]] = load i8, i8* [[C2]], align 1 ; IS________OPM-NEXT: call void @usei8(i8 [[L]]) -; IS________OPM-NEXT: call void @no_sync_func(i8* nocapture nofree noundef [[M]]) #[[ATTR5:[0-9]+]] +; IS________OPM-NEXT: call void @no_sync_func(i8* nocapture nofree noundef [[C2]]) #[[ATTR5:[0-9]+]] ; IS________OPM-NEXT: br label [[J]] ; IS________OPM: dead: ; IS________OPM-NEXT: unreachable @@ -536,9 +538,10 @@ define i32 @irreducible_cfg(i32 %0) { ; IS________OPM-NEXT: br label [[TMP8]] ; IS________OPM: 15: ; IS________OPM-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4 -; IS________OPM-NEXT: call void @free(i8* nocapture noundef [[TMP2]]) -; IS________OPM-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4 -; IS________OPM-NEXT: ret i32 [[TMP17]] +; IS________OPM-NEXT: [[TMP17:%.*]] = bitcast i32* [[TMP3]] to i8* +; IS________OPM-NEXT: call void @free(i8* nocapture noundef [[TMP17]]) +; IS________OPM-NEXT: [[TMP18:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________OPM-NEXT: ret i32 [[TMP18]] ; ; IS________NPM-LABEL: define {{[^@]+}}@irreducible_cfg ; IS________NPM-SAME: (i32 [[TMP0:%.*]]) { diff --git a/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll b/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll index f2fe9ef20818..cb74ed43cd73 100644 --- a/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll +++ b/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll @@ -377,36 +377,68 @@ define void @test11() { ; TEST 12 define i32 @irreducible_cfg(i32 %0) { -; CHECK-LABEL: define {{[^@]+}}@irreducible_cfg -; CHECK-SAME: (i32 [[TMP0:%.*]]) { -; CHECK-NEXT: [[TMP2:%.*]] = call noalias i8* @malloc(i64 noundef 4) -; CHECK-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32* -; CHECK-NEXT: store i32 10, i32* [[TMP3]], align 4 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1 -; CHECK-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]] -; CHECK: 5: -; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5 -; CHECK-NEXT: br label [[TMP13:%.*]] -; CHECK: 7: -; CHECK-NEXT: br label [[TMP8:%.*]] -; CHECK: 8: -; CHECK-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ] -; CHECK-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4 -; CHECK-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1 -; CHECK-NEXT: store i32 [[TMP10]], i32* [[TMP3]], align 4 -; CHECK-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0 -; CHECK-NEXT: br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]] -; CHECK: 12: -; CHECK-NEXT: br label [[TMP13]] -; CHECK: 13: -; CHECK-NEXT: [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ] -; CHECK-NEXT: [[TMP14]] = add nsw i32 [[DOT1]], 1 -; CHECK-NEXT: br label [[TMP8]] -; CHECK: 15: -; CHECK-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4 -; CHECK-NEXT: call void @free(i8* nocapture noundef [[TMP2]]) -; CHECK-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4 -; CHECK-NEXT: ret i32 [[TMP17]] +; IS________OPM-LABEL: define {{[^@]+}}@irreducible_cfg +; IS________OPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________OPM-NEXT: [[TMP2:%.*]] = call noalias i8* @malloc(i64 noundef 4) +; IS________OPM-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32* +; IS________OPM-NEXT: store i32 10, i32* [[TMP3]], align 4 +; IS________OPM-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1 +; IS________OPM-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]] +; IS________OPM: 5: +; IS________OPM-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5 +; IS________OPM-NEXT: br label [[TMP13:%.*]] +; IS________OPM: 7: +; IS________OPM-NEXT: br label [[TMP8:%.*]] +; IS________OPM: 8: +; IS________OPM-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ] +; IS________OPM-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________OPM-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1 +; IS________OPM-NEXT: store i32 [[TMP10]], i32* [[TMP3]], align 4 +; IS________OPM-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0 +; IS________OPM-NEXT: br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]] +; IS________OPM: 12: +; IS________OPM-NEXT: br label [[TMP13]] +; IS________OPM: 13: +; IS________OPM-NEXT: [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ] +; IS________OPM-NEXT: [[TMP14]] = add nsw i32 [[DOT1]], 1 +; IS________OPM-NEXT: br label [[TMP8]] +; IS________OPM: 15: +; IS________OPM-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________OPM-NEXT: [[TMP17:%.*]] = bitcast i32* [[TMP3]] to i8* +; IS________OPM-NEXT: call void @free(i8* nocapture noundef [[TMP17]]) +; IS________OPM-NEXT: [[TMP18:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________OPM-NEXT: ret i32 [[TMP18]] +; +; IS________NPM-LABEL: define {{[^@]+}}@irreducible_cfg +; IS________NPM-SAME: (i32 [[TMP0:%.*]]) { +; IS________NPM-NEXT: [[TMP2:%.*]] = call noalias i8* @malloc(i64 noundef 4) +; IS________NPM-NEXT: [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32* +; IS________NPM-NEXT: store i32 10, i32* [[TMP3]], align 4 +; IS________NPM-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1 +; IS________NPM-NEXT: br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]] +; IS________NPM: 5: +; IS________NPM-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5 +; IS________NPM-NEXT: br label [[TMP13:%.*]] +; IS________NPM: 7: +; IS________NPM-NEXT: br label [[TMP8:%.*]] +; IS________NPM: 8: +; IS________NPM-NEXT: [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ] +; IS________NPM-NEXT: [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________NPM-NEXT: [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1 +; IS________NPM-NEXT: store i32 [[TMP10]], i32* [[TMP3]], align 4 +; IS________NPM-NEXT: [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0 +; IS________NPM-NEXT: br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]] +; IS________NPM: 12: +; IS________NPM-NEXT: br label [[TMP13]] +; IS________NPM: 13: +; IS________NPM-NEXT: [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ] +; IS________NPM-NEXT: [[TMP14]] = add nsw i32 [[DOT1]], 1 +; IS________NPM-NEXT: br label [[TMP8]] +; IS________NPM: 15: +; IS________NPM-NEXT: [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________NPM-NEXT: call void @free(i8* nocapture noundef [[TMP2]]) +; IS________NPM-NEXT: [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4 +; IS________NPM-NEXT: ret i32 [[TMP17]] ; %2 = call noalias i8* @malloc(i64 4) %3 = bitcast i8* %2 to i32* diff --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll index a28de51ed839..60cf10019c16 100644 --- a/llvm/test/Transforms/Attributor/memory_locations.ll +++ b/llvm/test/Transforms/Attributor/memory_locations.ll @@ -639,20 +639,20 @@ define internal i8 @recursive_not_readnone_internal2(i8* %ptr, i1 %c) { ; IS__TUNIT____-NEXT: [[R:%.*]] = load i8, i8* [[ALLOC]], align 1 ; IS__TUNIT____-NEXT: ret i8 [[R]] ; IS__TUNIT____: f: -; IS__TUNIT____-NEXT: store i8 1, i8* [[ALLOC]], align 1 +; IS__TUNIT____-NEXT: store i8 1, i8* [[PTR]], align 1 ; IS__TUNIT____-NEXT: ret i8 0 ; -; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone +; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind ; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_not_readnone_internal2 -; IS__CGSCC____-SAME: (i8* noalias nocapture nofree nonnull readnone [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR9]] { +; IS__CGSCC____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { ; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 ; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; IS__CGSCC____: t: -; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal2(i8* noalias nocapture nofree nonnull readnone dereferenceable(1) undef, i1 noundef false) #[[ATTR9]] +; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11]] ; IS__CGSCC____-NEXT: [[R:%.*]] = load i8, i8* [[ALLOC]], align 1 ; IS__CGSCC____-NEXT: ret i8 [[R]] ; IS__CGSCC____: f: -; IS__CGSCC____-NEXT: store i8 1, i8* [[ALLOC]], align 1 +; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1 ; IS__CGSCC____-NEXT: ret i8 0 ; %alloc = alloca i8 @@ -676,7 +676,7 @@ define i8 @readnone_caller2(i1 %c) { ; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone ; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller2 ; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] { -; IS__CGSCC____-NEXT: [[R:%.*]] = call i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR13:[0-9]+]] +; IS__CGSCC____-NEXT: [[R:%.*]] = call i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR12]] ; IS__CGSCC____-NEXT: ret i8 [[R]] ; %r = call i8 @recursive_not_readnone_internal2(i8* undef, i1 %c) @@ -742,5 +742,4 @@ define void @argmemonky_caller() { ; IS__CGSCC____: attributes #[[ATTR10]] = { nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR11]] = { nofree nosync nounwind } ; IS__CGSCC____: attributes #[[ATTR12]] = { nounwind } -; IS__CGSCC____: attributes #[[ATTR13]] = { nounwind readnone } ;. diff --git a/llvm/test/Transforms/Attributor/noalias.ll b/llvm/test/Transforms/Attributor/noalias.ll index 60ec42913ff3..e28fd41c7eec 100644 --- a/llvm/test/Transforms/Attributor/noalias.ll +++ b/llvm/test/Transforms/Attributor/noalias.ll @@ -417,11 +417,13 @@ define void @test12_4(){ ; IS________OPM-LABEL: define {{[^@]+}}@test12_4() { ; IS________OPM-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) ; IS________OPM-NEXT: [[B:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; IS________OPM-NEXT: [[A_0:%.*]] = getelementptr i8, i8* [[A]], i64 0 ; IS________OPM-NEXT: [[A_1:%.*]] = getelementptr i8, i8* [[A]], i64 1 +; IS________OPM-NEXT: [[B_0:%.*]] = getelementptr i8, i8* [[B]], i64 0 ; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[B]]) -; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A]]) +; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_0]]) ; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_1]]) -; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[B]]) +; IS________OPM-NEXT: tail call void @two_args(i8* nocapture [[A_0]], i8* nocapture [[B_0]]) ; IS________OPM-NEXT: ret void ; ; NOT_TUNIT_OPM-LABEL: define {{[^@]+}}@test12_4() { @@ -463,10 +465,17 @@ define void @use_i8_internal(i8* %a) { } define void @test13_use_noalias(){ -; CHECK-LABEL: define {{[^@]+}}@test13_use_noalias() { -; CHECK-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; CHECK-NEXT: call void @use_i8_internal(i8* noalias nocapture [[M1]]) -; CHECK-NEXT: ret void +; IS________OPM-LABEL: define {{[^@]+}}@test13_use_noalias() { +; IS________OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; IS________OPM-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16* +; IS________OPM-NEXT: [[C2:%.*]] = bitcast i16* [[C1]] to i8* +; IS________OPM-NEXT: call void @use_i8_internal(i8* noalias nocapture [[C2]]) +; IS________OPM-NEXT: ret void +; +; NOT_TUNIT_OPM-LABEL: define {{[^@]+}}@test13_use_noalias() { +; NOT_TUNIT_OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; NOT_TUNIT_OPM-NEXT: call void @use_i8_internal(i8* noalias nocapture [[M1]]) +; NOT_TUNIT_OPM-NEXT: ret void ; ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test13_use_noalias() ; IS__CGSCC_OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 4) @@ -482,11 +491,20 @@ define void @test13_use_noalias(){ } define void @test13_use_alias(){ -; CHECK-LABEL: define {{[^@]+}}@test13_use_alias() { -; CHECK-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) -; CHECK-NEXT: call void @use_i8_internal(i8* nocapture [[M1]]) -; CHECK-NEXT: call void @use_i8_internal(i8* nocapture [[M1]]) -; CHECK-NEXT: ret void +; IS________OPM-LABEL: define {{[^@]+}}@test13_use_alias() { +; IS________OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; IS________OPM-NEXT: [[C1:%.*]] = bitcast i8* [[M1]] to i16* +; IS________OPM-NEXT: [[C2A:%.*]] = bitcast i16* [[C1]] to i8* +; IS________OPM-NEXT: [[C2B:%.*]] = bitcast i16* [[C1]] to i8* +; IS________OPM-NEXT: call void @use_i8_internal(i8* nocapture [[C2A]]) +; IS________OPM-NEXT: call void @use_i8_internal(i8* nocapture [[C2B]]) +; IS________OPM-NEXT: ret void +; +; NOT_TUNIT_OPM-LABEL: define {{[^@]+}}@test13_use_alias() { +; NOT_TUNIT_OPM-NEXT: [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4) +; NOT_TUNIT_OPM-NEXT: call void @use_i8_internal(i8* nocapture [[M1]]) +; NOT_TUNIT_OPM-NEXT: call void @use_i8_internal(i8* nocapture [[M1]]) +; NOT_TUNIT_OPM-NEXT: ret void ; %m1 = tail call noalias i8* @malloc(i64 4) %c1 = bitcast i8* %m1 to i16* diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll index d3f73c3a2650..f1b0de6499b9 100644 --- a/llvm/test/Transforms/Attributor/nonnull.ll +++ b/llvm/test/Transforms/Attributor/nonnull.ll @@ -276,7 +276,7 @@ define i8* @test6b(i1 %c) { ; CHECK-NEXT: [[PHI:%.*]] = phi i8* [ [[RET]], [[ENTRY:%.*]] ], [ [[PHI]], [[LOOP]] ] ; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* [[PHI]] ; entry: %ret = call i8* @ret_nonnull() diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll index 978c9718874d..8640f7671e3d 100644 --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -1218,6 +1218,47 @@ define internal i1 @cmp_null_after_cast(i32 %a, i8 %b) { ret i1 %c } + +declare i8* @m() + +define i32 @test(i1 %c) { +; CHECK-LABEL: define {{[^@]+}}@test +; CHECK-SAME: (i1 [[C:%.*]]) { +; CHECK-NEXT: [[R:%.*]] = call i32 @ctx_test(i1 [[C]]) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ctx_test(i1 %c) + ret i32 %r +} + +define internal i32 @ctx_test(i1 %c) { +; CHECK-LABEL: define {{[^@]+}}@ctx_test +; CHECK-SAME: (i1 [[C:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]] +; CHECK: then: +; CHECK-NEXT: [[M:%.*]] = tail call i8* @m() +; CHECK-NEXT: [[I:%.*]] = ptrtoint i8* [[M]] to i64 +; CHECK-NEXT: br label [[JOIN]] +; CHECK: join: +; CHECK-NEXT: [[PHI:%.*]] = phi i64 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[RET:%.*]] = trunc i64 [[PHI]] to i32 +; CHECK-NEXT: ret i32 [[RET]] +; +entry: + br i1 %c, label %then, label %join + +then: + %m = tail call i8* @m() + %i = ptrtoint i8* %m to i64 + br label %join + +join: + %phi = phi i64 [ %i, %then ], [ undef, %entry ] + %ret = trunc i64 %phi to i32 + ret i32 %ret +} + ;. ; IS__TUNIT_OPM: attributes #[[ATTR0]] = { nofree nosync nounwind willreturn } ; IS__TUNIT_OPM: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn }