[SCEV] Use guards to prove predicates

We can use calls to @llvm.experimental.guard to prove predicates,
relying on the fact that in all locations domianted by a call to
@llvm.experimental.guard the predicate it is guarding is known to be
true.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@268997 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjoy Das 2016-05-10 00:31:49 +00:00
parent e598f97f6c
commit cbda428c36
3 changed files with 196 additions and 3 deletions

View File

@ -464,6 +464,12 @@ namespace llvm {
///
Function &F;
/// Does the module have any calls to the llvm.experimental.guard intrinsic
/// at all? If this is false, we avoid doing work that will only help if
/// thare are guards present in the IR.
///
bool HasGuards;
/// The target library information for the target we are targeting.
///
TargetLibraryInfo &TLI;
@ -1007,6 +1013,11 @@ namespace llvm {
const SCEV *FoundLHS,
const SCEV *FoundRHS);
/// Return true if the condition denoted by \p LHS \p Pred \p RHS is implied
/// by a call to \c @llvm.experimental.guard in \p BB.
bool isImpliedViaGuard(BasicBlock *BB, ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS);
/// Test whether the condition described by Pred, LHS, and RHS is true
/// whenever the condition described by Pred, FoundLHS, and FoundRHS is
/// true.

View File

@ -7805,6 +7805,23 @@ bool ScalarEvolution::isKnownPredicateViaSplitting(ICmpInst::Predicate Pred,
isKnownPredicate(CmpInst::ICMP_SLT, LHS, RHS);
}
bool ScalarEvolution::isImpliedViaGuard(BasicBlock *BB,
ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS) {
// No need to even try if we know the module has no guards.
if (!HasGuards)
return false;
return any_of(*BB, [&](Instruction &I) {
using namespace llvm::PatternMatch;
Value *Condition;
return match(&I, m_Intrinsic<Intrinsic::experimental_guard>(
m_Value(Condition))) &&
isImpliedCond(Pred, LHS, RHS, Condition, false);
});
}
/// isLoopBackedgeGuardedByCond - Test whether the backedge of the loop is
/// protected by a conditional between LHS and RHS. This is used to
/// to eliminate casts.
@ -7872,12 +7889,18 @@ ScalarEvolution::isLoopBackedgeGuardedByCond(const Loop *L,
if (!DT.isReachableFromEntry(L->getHeader()))
return false;
if (isImpliedViaGuard(Latch, Pred, LHS, RHS))
return true;
for (DomTreeNode *DTN = DT[Latch], *HeaderDTN = DT[L->getHeader()];
DTN != HeaderDTN; DTN = DTN->getIDom()) {
assert(DTN && "should reach the loop header before reaching the root!");
BasicBlock *BB = DTN->getBlock();
if (isImpliedViaGuard(BB, Pred, LHS, RHS))
return true;
BasicBlock *PBB = BB->getSinglePredecessor();
if (!PBB)
continue;
@ -7930,6 +7953,9 @@ ScalarEvolution::isLoopEntryGuardedByCond(const Loop *L,
Pair.first;
Pair = getPredecessorWithUniqueSuccessorForBB(Pair.first)) {
if (isImpliedViaGuard(Pair.first, Pred, LHS, RHS))
return true;
BranchInst *LoopEntryPredicate =
dyn_cast<BranchInst>(Pair.first->getTerminator());
if (!LoopEntryPredicate ||
@ -9462,11 +9488,26 @@ ScalarEvolution::ScalarEvolution(Function &F, TargetLibraryInfo &TLI,
CouldNotCompute(new SCEVCouldNotCompute()),
WalkingBEDominatingConds(false), ProvingSplitPredicate(false),
ValuesAtScopes(64), LoopDispositions(64), BlockDispositions(64),
FirstUnknown(nullptr) {}
FirstUnknown(nullptr) {
// To use guards for proving predicates, we need to scan every instruction in
// relevant basic blocks, and not just terminators. Doing this is a waste of
// time if the IR does not actually contain any calls to
// @llvm.experimental.guard, so do a quick check and remember this beforehand.
//
// This pessimizes the case where a pass that preserves ScalarEvolution wants
// to _add_ guards to the module when there weren't any before, and wants
// ScalarEvolution to optimize based on those guards. For now we prefer to be
// efficient in lieu of being smart in that rather obscure case.
auto *GuardDecl = F.getParent()->getFunction(
Intrinsic::getName(Intrinsic::experimental_guard));
HasGuards = GuardDecl && !GuardDecl->use_empty();
}
ScalarEvolution::ScalarEvolution(ScalarEvolution &&Arg)
: F(Arg.F), TLI(Arg.TLI), AC(Arg.AC), DT(Arg.DT), LI(Arg.LI),
CouldNotCompute(std::move(Arg.CouldNotCompute)),
: F(Arg.F), HasGuards(Arg.HasGuards), TLI(Arg.TLI), AC(Arg.AC), DT(Arg.DT),
LI(Arg.LI), CouldNotCompute(std::move(Arg.CouldNotCompute)),
ValueExprMap(std::move(Arg.ValueExprMap)),
WalkingBEDominatingConds(false), ProvingSplitPredicate(false),
BackedgeTakenCounts(std::move(Arg.BackedgeTakenCounts)),

View File

@ -0,0 +1,141 @@
; RUN: opt -S -indvars < %s | FileCheck %s
; Check that SCEV is able to recognize and use guards to prove
; conditions gaurding loop entries and backedges. This isn't intended
; to be a comprehensive test of SCEV's simplification capabilities,
; tests directly testing e.g. if SCEV can elide a sext should go
; elsewhere.
target datalayout = "n8:16:32:64"
declare void @llvm.experimental.guard(i1, ...)
define void @test_1(i1* %cond_buf, i32* %len_buf) {
; CHECK-LABEL: @test_1(
entry:
%len = load i32, i32* %len_buf, !range !{i32 1, i32 2147483648}
br label %loop
loop:
; CHECK: loop:
; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
; CHECK: %iv.inc.cmp = icmp slt i32 %iv.inc, %len
; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
; CHECK: leave:
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
%iv.inc = add i32 %iv, 1
%iv.cmp = icmp slt i32 %iv, %len
call void(i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
%iv.inc.cmp = icmp slt i32 %iv.inc, %len
call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
%becond = load volatile i1, i1* %cond_buf
br i1 %becond, label %loop, label %leave
leave:
ret void
}
define void @test_2(i32 %n, i32* %len_buf) {
; CHECK-LABEL: @test_2(
; CHECK: [[LEN_SEXT:%[^ ]+]] = sext i32 %len to i64
; CHECK: br label %loop
entry:
%len = load i32, i32* %len_buf, !range !{i32 0, i32 2147483648}
br label %loop
loop:
; CHECK: loop:
; CHECK: %indvars.iv = phi i64 [ %indvars.iv.next, %loop ], [ 0, %entry ]
; CHECK: %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
; CHECK: %iv.inc.cmp = icmp slt i64 %indvars.iv.next, [[LEN_SEXT]]
; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
; CHECK: leave:
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
%iv.inc = add i32 %iv, 1
%iv.sext = sext i32 %iv to i64
%iv.inc.cmp = icmp slt i32 %iv.inc, %len
call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
%becond = icmp ne i32 %iv, %n
br i1 %becond, label %loop, label %leave
leave:
ret void
}
define void @test_3(i1* %cond_buf, i32* %len_buf) {
; CHECK-LABEL: @test_3(
entry:
%len = load i32, i32* %len_buf
%entry.cond = icmp sgt i32 %len, 0
call void(i1, ...) @llvm.experimental.guard(i1 %entry.cond) [ "deopt"() ]
br label %loop
loop:
; CHECK: loop:
; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
; CHECK: %iv.inc.cmp = icmp slt i32 %iv.inc, %len
; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
; CHECK: leave:
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
%iv.inc = add i32 %iv, 1
%iv.cmp = icmp slt i32 %iv, %len
call void(i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
%iv.inc.cmp = icmp slt i32 %iv.inc, %len
call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
%becond = load volatile i1, i1* %cond_buf
br i1 %becond, label %loop, label %leave
leave:
ret void
}
define void @test_4(i1* %cond_buf, i32* %len_buf) {
; CHECK-LABEL: @test_4(
entry:
%len = load i32, i32* %len_buf
%entry.cond = icmp sgt i32 %len, 0
call void(i1, ...) @llvm.experimental.guard(i1 %entry.cond) [ "deopt"() ]
br label %loop
loop:
%iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ]
%iv.inc = add i32 %iv, 1
%cond = load volatile i1, i1* %cond_buf
br i1 %cond, label %left, label %be
left:
; Does not dominate the backedge, so cannot be used in the inductive proof
%iv.inc.cmp = icmp slt i32 %iv.inc, %len
call void(i1, ...) @llvm.experimental.guard(i1 %iv.inc.cmp) [ "deopt"() ]
br label %be
be:
; CHECK: be:
; CHECK-NEXT: %iv.cmp = icmp slt i32 %iv, %len
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
; CHECK: leave:
%iv.cmp = icmp slt i32 %iv, %len
call void(i1, ...) @llvm.experimental.guard(i1 %iv.cmp) [ "deopt"() ]
%becond = load volatile i1, i1* %cond_buf
br i1 %becond, label %loop, label %leave
leave:
ret void
}