1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00

[Attributor][FIX] Do not replace a value with a non-dominating instruction

We have to be careful when we replace values to not use a non-dominating
instruction. It makes sense that simplification offers those as
"simplified values" but we can't manifest them in the IR without PHI
nodes. In the future we should consider potentially adding those PHI
nodes.
This commit is contained in:
Johannes Doerfert 2021-06-24 13:12:06 -05:00
parent aca5749760
commit 0e688881f2
12 changed files with 502 additions and 205 deletions

View File

@ -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.

View File

@ -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<Constant>(V))
return true;
const Function *Scope = CtxI.getFunction();
if (auto *A = dyn_cast<Argument>(&V))
return A->getParent() == Scope;
if (auto *I = dyn_cast<Instruction>(&V))
if (I->getFunction() == Scope) {
const DominatorTree *DT =
InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*Scope);
return DT && DT->dominates(I, &CtxI);
}
return false;
}
Value *AA::getWithType(Value &V, Type &Ty) {
if (V.getType() == &Ty)
return &V;

View File

@ -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<ReturnInst *, 4> &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<CallBase>(&getAnchorValue())
->getArgOperandUse(getCallSiteArgNo());
if (A.changeUseAfterManifest(U, *NewV))

View File

@ -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 }
;.

View File

@ -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 }
;.

View File

@ -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 }
;.

View File

@ -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:%.*]]) {

View File

@ -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*

View File

@ -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 }
;.

View File

@ -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*

View File

@ -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()

View File

@ -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 }