mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 13:11:39 +01:00
[ValueTracking] Teach isKnownNonNullFromDominatingCondition about AND
`isKnownNonNullFromDominatingCondition` is able to prove non-null basing on `br` or `guard` by `%p != null` condition, but is unable to do so basing on `(%p != null) && %other_cond`. This patch allows it to do so. Differential Revision: https://reviews.llvm.org/D50172 Reviewed By: reames llvm-svn: 338990
This commit is contained in:
parent
ab15b0a38f
commit
4217d9c40c
@ -1861,18 +1861,36 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V,
|
||||
continue;
|
||||
|
||||
for (auto *CmpU : U->users()) {
|
||||
if (const BranchInst *BI = dyn_cast<BranchInst>(CmpU)) {
|
||||
assert(BI->isConditional() && "uses a comparison!");
|
||||
SmallVector<const User *, 4> WorkList;
|
||||
SmallPtrSet<const User *, 4> Visited;
|
||||
Visited.insert(CmpU);
|
||||
WorkList.push_back(CmpU);
|
||||
|
||||
BasicBlock *NonNullSuccessor =
|
||||
BI->getSuccessor(Pred == ICmpInst::ICMP_EQ ? 1 : 0);
|
||||
BasicBlockEdge Edge(BI->getParent(), NonNullSuccessor);
|
||||
if (Edge.isSingleEdge() && DT->dominates(Edge, CtxI->getParent()))
|
||||
while (!WorkList.empty()) {
|
||||
auto *Curr = WorkList.pop_back_val();
|
||||
|
||||
// If a user is an AND, add all its users to the work list.
|
||||
if (auto *BO = dyn_cast<BinaryOperator>(Curr))
|
||||
if (BO->getOpcode() == Instruction::And) {
|
||||
for (auto *BOU : BO->users())
|
||||
if (Visited.insert(BOU).second)
|
||||
WorkList.push_back(BOU);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const BranchInst *BI = dyn_cast<BranchInst>(Curr)) {
|
||||
assert(BI->isConditional() && "uses a comparison!");
|
||||
|
||||
BasicBlock *NonNullSuccessor =
|
||||
BI->getSuccessor(Pred == ICmpInst::ICMP_EQ ? 1 : 0);
|
||||
BasicBlockEdge Edge(BI->getParent(), NonNullSuccessor);
|
||||
if (Edge.isSingleEdge() && DT->dominates(Edge, CtxI->getParent()))
|
||||
return true;
|
||||
} else if (Pred == ICmpInst::ICMP_NE &&
|
||||
match(Curr, m_Intrinsic<Intrinsic::experimental_guard>()) &&
|
||||
DT->dominates(cast<Instruction>(Curr), CtxI)) {
|
||||
return true;
|
||||
} else if (Pred == ICmpInst::ICMP_NE &&
|
||||
match(CmpU, m_Intrinsic<Intrinsic::experimental_guard>()) &&
|
||||
DT->dominates(cast<Instruction>(CmpU), CtxI)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,5 +556,87 @@ for.end: ; preds = %for.inc, %entry, %e
|
||||
ret void
|
||||
}
|
||||
|
||||
; Check that branch by condition "null check AND something" allows to hoist the
|
||||
; load.
|
||||
define void @test14(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n, i1 %dummy_cond) #0 {
|
||||
|
||||
; CHECK-LABEL: @test14
|
||||
; CHECK: load i32, i32* %c, align 4
|
||||
; CHECK: for.body:
|
||||
|
||||
entry:
|
||||
%not_null = icmp ne i32* %c, null
|
||||
%dummy_and = and i1 %not_null, %dummy_cond
|
||||
br i1 %dummy_and, label %not.null, label %for.end
|
||||
|
||||
not.null:
|
||||
%cmp11 = icmp sgt i32 %n, 0
|
||||
br i1 %cmp11, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %not.null, %for.inc
|
||||
%indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %not.null ]
|
||||
%arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv
|
||||
%0 = load i32, i32* %arrayidx, align 4
|
||||
%cmp1 = icmp sgt i32 %0, 0
|
||||
br i1 %cmp1, label %if.then, label %for.inc
|
||||
|
||||
if.then: ; preds = %for.body
|
||||
%1 = load i32, i32* %c, align 4
|
||||
%arrayidx3 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv
|
||||
%2 = load i32, i32* %arrayidx3, align 4
|
||||
%mul = mul nsw i32 %2, %1
|
||||
store i32 %mul, i32* %arrayidx, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body, %if.then
|
||||
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
|
||||
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
|
||||
%exitcond = icmp eq i32 %lftr.wideiv, %n
|
||||
br i1 %exitcond, label %for.end, label %for.body
|
||||
|
||||
for.end: ; preds = %for.inc, %entry, %not.null
|
||||
ret void
|
||||
}
|
||||
|
||||
; Check that guard by condition "null check AND something" allows to hoist the
|
||||
; load.
|
||||
define void @test15(i32* noalias %a, i32* %b, i32* dereferenceable_or_null(4) %c, i32 %n, i1 %dummy_cond) #0 {
|
||||
|
||||
; CHECK-LABEL: @test15
|
||||
; CHECK: load i32, i32* %c, align 4
|
||||
; CHECK: for.body:
|
||||
|
||||
entry:
|
||||
%not_null = icmp ne i32* %c, null
|
||||
%dummy_and = and i1 %not_null, %dummy_cond
|
||||
call void(i1, ...) @llvm.experimental.guard(i1 %dummy_and) [ "deopt"() ]
|
||||
%cmp11 = icmp sgt i32 %n, 0
|
||||
br i1 %cmp11, label %for.body, label %for.end
|
||||
|
||||
for.body: ; preds = %entry, %for.inc
|
||||
%indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
|
||||
%arrayidx = getelementptr inbounds i32, i32* %a, i64 %indvars.iv
|
||||
%0 = load i32, i32* %arrayidx, align 4
|
||||
%cmp1 = icmp sgt i32 %0, 0
|
||||
br i1 %cmp1, label %if.then, label %for.inc
|
||||
|
||||
if.then: ; preds = %for.body
|
||||
%1 = load i32, i32* %c, align 4
|
||||
%arrayidx3 = getelementptr inbounds i32, i32* %b, i64 %indvars.iv
|
||||
%2 = load i32, i32* %arrayidx3, align 4
|
||||
%mul = mul nsw i32 %2, %1
|
||||
store i32 %mul, i32* %arrayidx, align 4
|
||||
br label %for.inc
|
||||
|
||||
for.inc: ; preds = %for.body, %if.then
|
||||
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
|
||||
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
|
||||
%exitcond = icmp eq i32 %lftr.wideiv, %n
|
||||
br i1 %exitcond, label %for.end, label %for.body
|
||||
|
||||
for.end: ; preds = %for.inc, %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
||||
!0 = !{i64 4}
|
||||
|
Loading…
x
Reference in New Issue
Block a user