forked from OSchip/llvm-project
[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:
parent
a83b6cc176
commit
13e63a2f21
|
@ -29,6 +29,7 @@
|
|||
#include "llvm/Analysis/Loads.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/TargetLibraryInfo.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/IntrinsicInst.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::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 {
|
||||
// These are at global scope so static functions can use them too.
|
||||
typedef SmallVectorImpl<std::pair<Constant*, BasicBlock*> > PredValueInfo;
|
||||
|
@ -151,6 +159,7 @@ namespace {
|
|||
|
||||
bool ProcessBranchOnPHI(PHINode *PN);
|
||||
bool ProcessBranchOnXOR(BinaryOperator *BO);
|
||||
bool ProcessImpliedCondition(BasicBlock *BB);
|
||||
|
||||
bool SimplifyPartiallyRedundantLoad(LoadInst *LI);
|
||||
bool TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB);
|
||||
|
@ -868,9 +877,38 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) {
|
|||
CondInst->getParent() == BB && isa<BranchInst>(BB->getTerminator()))
|
||||
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
|
||||
// "(X == 4)", thread through this block.
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue