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/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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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