[JumpThreading] Use dominating conditions to prove implications

Summary:
If P branches to Q conditional on C and Q branches to R conditional on
C' and C => C' then the branch conditional on C' can be folded to an
unconditional branch.

Reviewers: reames

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D13972

llvm-svn: 251557
This commit is contained in:
Sanjoy Das 2015-10-28 21:27:08 +00:00
parent a83b6cc176
commit 13e63a2f21
2 changed files with 138 additions and 2 deletions

View File

@ -29,6 +29,7 @@
#include "llvm/Analysis/Loads.h" #include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h" #include "llvm/IR/DataLayout.h"
#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
@ -57,6 +58,13 @@ BBDuplicateThreshold("jump-threading-threshold",
cl::desc("Max block size to duplicate for jump threading"), cl::desc("Max block size to duplicate for jump threading"),
cl::init(6), cl::Hidden); cl::init(6), cl::Hidden);
static cl::opt<unsigned>
ImplicationSearchThreshold(
"jump-threading-implication-search-threshold",
cl::desc("The number of predecessors to search for a stronger "
"condition to use to thread over a weaker condition"),
cl::init(3), cl::Hidden);
namespace { namespace {
// These are at global scope so static functions can use them too. // These are at global scope so static functions can use them too.
typedef SmallVectorImpl<std::pair<Constant*, BasicBlock*> > PredValueInfo; typedef SmallVectorImpl<std::pair<Constant*, BasicBlock*> > PredValueInfo;
@ -151,6 +159,7 @@ namespace {
bool ProcessBranchOnPHI(PHINode *PN); bool ProcessBranchOnPHI(PHINode *PN);
bool ProcessBranchOnXOR(BinaryOperator *BO); bool ProcessBranchOnXOR(BinaryOperator *BO);
bool ProcessImpliedCondition(BasicBlock *BB);
bool SimplifyPartiallyRedundantLoad(LoadInst *LI); bool SimplifyPartiallyRedundantLoad(LoadInst *LI);
bool TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB); bool TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB);
@ -868,9 +877,38 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) {
CondInst->getParent() == BB && isa<BranchInst>(BB->getTerminator())) CondInst->getParent() == BB && isa<BranchInst>(BB->getTerminator()))
return ProcessBranchOnXOR(cast<BinaryOperator>(CondInst)); return ProcessBranchOnXOR(cast<BinaryOperator>(CondInst));
// Search for a stronger dominating condition that can be used to simplify a
// conditional branch leaving BB.
if (ProcessImpliedCondition(BB))
return true;
// TODO: If we have: "br (X > 0)" and we have a predecessor where we know return false;
// "(X == 4)", thread through this block. }
bool JumpThreading::ProcessImpliedCondition(BasicBlock *BB) {
auto *BI = dyn_cast<BranchInst>(BB->getTerminator());
if (!BI || !BI->isConditional())
return false;
Value *Cond = BI->getCondition();
BasicBlock *CurrentBB = BB;
BasicBlock *CurrentPred = BB->getSinglePredecessor();
unsigned Iter = 0;
while (CurrentPred && Iter++ < ImplicationSearchThreshold) {
auto *PBI = dyn_cast<BranchInst>(CurrentPred->getTerminator());
if (!PBI || !PBI->isConditional() || PBI->getSuccessor(0) != CurrentBB)
return false;
if (isImpliedCondition(PBI->getCondition(), Cond)) {
BI->getSuccessor(1)->removePredecessor(BB);
BranchInst::Create(BI->getSuccessor(0), BI);
BI->eraseFromParent();
return true;
}
CurrentBB = CurrentPred;
CurrentPred = CurrentBB->getSinglePredecessor();
}
return false; return false;
} }

View File

@ -0,0 +1,98 @@
; RUN: opt -jump-threading -S < %s | FileCheck %s
declare void @side_effect(i32)
define void @test0(i32 %i, i32 %len) {
; CHECK-LABEL: @test0(
entry:
call void @side_effect(i32 0)
%i.inc = add nuw i32 %i, 1
%c0 = icmp ult i32 %i.inc, %len
br i1 %c0, label %left, label %right
left:
; CHECK: entry:
; CHECK: br i1 %c0, label %left0, label %right
; CHECK: left0:
; CHECK: call void @side_effect
; CHECK-NOT: br i1 %c1
; CHECK: call void @side_effect
call void @side_effect(i32 0)
%c1 = icmp ult i32 %i, %len
br i1 %c1, label %left0, label %right
left0:
call void @side_effect(i32 0)
ret void
right:
%t = phi i32 [ 1, %left ], [ 2, %entry ]
call void @side_effect(i32 %t)
ret void
}
define void @test1(i32 %i, i32 %len) {
; CHECK-LABEL: @test1(
entry:
call void @side_effect(i32 0)
%i.inc = add nsw i32 %i, 1
%c0 = icmp slt i32 %i.inc, %len
br i1 %c0, label %left, label %right
left:
; CHECK: entry:
; CHECK: br i1 %c0, label %left0, label %right
; CHECK: left0:
; CHECK: call void @side_effect
; CHECK-NOT: br i1 %c1
; CHECK: call void @side_effect
call void @side_effect(i32 0)
%c1 = icmp slt i32 %i, %len
br i1 %c1, label %left0, label %right
left0:
call void @side_effect(i32 0)
ret void
right:
%t = phi i32 [ 1, %left ], [ 2, %entry ]
call void @side_effect(i32 %t)
ret void
}
define void @test2(i32 %i, i32 %len, i1* %c.ptr) {
; CHECK-LABEL: @test2(
; CHECK: entry:
; CHECK: br i1 %c0, label %cont, label %right
; CHECK: cont:
; CHECK: br i1 %c, label %left0, label %right
; CHECK: left0:
; CHECK: call void @side_effect(i32 0)
; CHECK: call void @side_effect(i32 0)
entry:
call void @side_effect(i32 0)
%i.inc = add nsw i32 %i, 1
%c0 = icmp slt i32 %i.inc, %len
br i1 %c0, label %cont, label %right
cont:
%c = load i1, i1* %c.ptr
br i1 %c, label %left, label %right
left:
call void @side_effect(i32 0)
%c1 = icmp slt i32 %i, %len
br i1 %c1, label %left0, label %right
left0:
call void @side_effect(i32 0)
ret void
right:
%t = phi i32 [ 1, %left ], [ 2, %entry ], [ 3, %cont ]
call void @side_effect(i32 %t)
ret void
}