forked from OSchip/llvm-project
Have isKnownNotFullPoison be smarter around control flow
Summary: (... while still not using a PostDomTree) The way we use isKnownNotFullPoison from SCEV today, the new CFG walking logic will not trigger for any realistic cases -- it will kick in only for situations where we could have merged the contiguous basic blocks anyway[0], since the poison generating instruction dominates all of its non-PHI uses (which are the only uses we consider right now). However, having this change in place will allow a later bugfix to break fewer llvm-lit tests. [0]: i.e. cases where block A branches to block B and B is A's only successor and A is B's only predecessor. Reviewers: broune, bjarke.roune Subscribers: mcrosier, llvm-commits Differential Revision: http://reviews.llvm.org/D19212 llvm-svn: 267175
This commit is contained in:
parent
8c6fb415fd
commit
a6155b659a
|
@ -3543,26 +3543,44 @@ bool llvm::isKnownNotFullPoison(const Instruction *PoisonI) {
|
|||
// Set of instructions that we have proved will yield poison if PoisonI
|
||||
// does.
|
||||
SmallSet<const Value *, 16> YieldsPoison;
|
||||
SmallSet<const BasicBlock *, 4> Visited;
|
||||
YieldsPoison.insert(PoisonI);
|
||||
Visited.insert(PoisonI->getParent());
|
||||
|
||||
for (BasicBlock::const_iterator I = PoisonI->getIterator(), E = BB->end();
|
||||
I != E; ++I) {
|
||||
if (&*I != PoisonI) {
|
||||
const Value *NotPoison = getGuaranteedNonFullPoisonOp(&*I);
|
||||
if (NotPoison != nullptr && YieldsPoison.count(NotPoison)) return true;
|
||||
if (!isGuaranteedToTransferExecutionToSuccessor(&*I))
|
||||
return false;
|
||||
}
|
||||
BasicBlock::const_iterator Begin = PoisonI->getIterator(), End = BB->end();
|
||||
|
||||
// Mark poison that propagates from I through uses of I.
|
||||
if (YieldsPoison.count(&*I)) {
|
||||
for (const User *User : I->users()) {
|
||||
const Instruction *UserI = cast<Instruction>(User);
|
||||
if (UserI->getParent() == BB && propagatesFullPoison(UserI))
|
||||
YieldsPoison.insert(User);
|
||||
unsigned Iter = 0;
|
||||
while (Iter++ < MaxDepth) {
|
||||
for (auto &I : make_range(Begin, End)) {
|
||||
if (&I != PoisonI) {
|
||||
const Value *NotPoison = getGuaranteedNonFullPoisonOp(&I);
|
||||
if (NotPoison != nullptr && YieldsPoison.count(NotPoison))
|
||||
return true;
|
||||
if (!isGuaranteedToTransferExecutionToSuccessor(&I))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mark poison that propagates from I through uses of I.
|
||||
if (YieldsPoison.count(&I)) {
|
||||
for (const User *User : I.users()) {
|
||||
const Instruction *UserI = cast<Instruction>(User);
|
||||
if (propagatesFullPoison(UserI))
|
||||
YieldsPoison.insert(User);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (auto *NextBB = BB->getSingleSuccessor()) {
|
||||
if (Visited.insert(NextBB).second) {
|
||||
BB = NextBB;
|
||||
Begin = BB->getFirstNonPHI()->getIterator();
|
||||
End = BB->end();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ loop:
|
|||
%i = phi i32 [ %nexti, %loop2 ], [ 0, %entry ]
|
||||
|
||||
; CHECK: %index32 =
|
||||
; CHECK: --> {%offset,+,1}<nw>
|
||||
; CHECK: --> {%offset,+,1}<nsw>
|
||||
%index32 = add nsw i32 %i, %offset
|
||||
|
||||
%ptr = getelementptr inbounds float, float* %input, i32 %index32
|
||||
|
@ -127,6 +127,80 @@ exit:
|
|||
ret void
|
||||
}
|
||||
|
||||
; Similar to test-add-not-header, but in this case the load
|
||||
; instruction may not be executed.
|
||||
define void @test-add-not-header3(float* %input, i32 %offset, i32 %numIterations,
|
||||
i1* %cond_buf) {
|
||||
; CHECK-LABEL: @test-add-not-header3
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [ %nexti, %loop2 ], [ 0, %entry ]
|
||||
|
||||
; CHECK: %index32 =
|
||||
; CHECK: --> {%offset,+,1}<nw>
|
||||
%index32 = add nsw i32 %i, %offset
|
||||
|
||||
%ptr = getelementptr inbounds float, float* %input, i32 %index32
|
||||
%nexti = add nsw i32 %i, 1
|
||||
%cond = load volatile i1, i1* %cond_buf
|
||||
br i1 %cond, label %loop2, label %exit
|
||||
loop2:
|
||||
%f = load float, float* %ptr, align 4
|
||||
%exitcond = icmp eq i32 %nexti, %numIterations
|
||||
br i1 %exitcond, label %exit, label %loop
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Same thing as test-add-not-header2, except we have a few extra
|
||||
; blocks.
|
||||
define void @test-add-not-header4(float* %input, i32 %offset, i32 %numIterations) {
|
||||
; CHECK-LABEL: @test-add-not-header4
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [ %nexti, %loop2 ], [ 0, %entry ]
|
||||
|
||||
; CHECK: %index32 =
|
||||
; CHECK: --> {%offset,+,1}<nsw>
|
||||
%index32 = add nsw i32 %i, %offset
|
||||
|
||||
%ptr = getelementptr inbounds float, float* %input, i32 %index32
|
||||
%nexti = add nsw i32 %i, 1
|
||||
br label %loop3
|
||||
loop3:
|
||||
br label %loop4
|
||||
loop4:
|
||||
br label %loop2
|
||||
loop2:
|
||||
%f = load float, float* %ptr, align 4
|
||||
%exitcond = icmp eq i32 %nexti, %numIterations
|
||||
br i1 %exitcond, label %exit, label %loop
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Demonstrate why we need a Visited set in llvm::isKnownNotFullPoison.
|
||||
define void @test-add-not-header5(float* %input, i32 %offset) {
|
||||
; CHECK-LABEL: @test-add-not-header5
|
||||
entry:
|
||||
br label %loop
|
||||
loop:
|
||||
%i = phi i32 [ %nexti, %loop ], [ 0, %entry ]
|
||||
|
||||
; CHECK: %index32 =
|
||||
; CHECK: --> {%offset,+,1}<nw>
|
||||
%index32 = add nsw i32 %i, %offset
|
||||
|
||||
%ptr = getelementptr inbounds float, float* %input, i32 %index32
|
||||
%nexti = add nsw i32 %i, 1
|
||||
br label %loop
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; The call instruction makes it not guaranteed that the add will be
|
||||
; executed, since it could run forever or throw an exception, so we
|
||||
; cannot assume that the UB is realized.
|
||||
|
|
Loading…
Reference in New Issue