Index: llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp +++ llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp @@ -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 @@ cl::desc("Max block size to duplicate for jump threading"), cl::init(6), cl::Hidden); +static cl::opt +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 > PredValueInfo; @@ -151,6 +159,7 @@ 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 @@ CondInst->getParent() == BB && isa(BB->getTerminator())) return ProcessBranchOnXOR(cast(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(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(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; } Index: llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll =================================================================== --- llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll +++ llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll @@ -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 +}