Index: llvm/include/llvm/IR/Dominators.h =================================================================== --- llvm/include/llvm/IR/Dominators.h +++ llvm/include/llvm/IR/Dominators.h @@ -172,6 +172,8 @@ /// never dominate the use. bool dominates(const BasicBlockEdge &BBE, const Use &U) const; bool dominates(const BasicBlockEdge &BBE, const BasicBlock *BB) const; + /// Returns true if edge \p BBE1 dominates edge \p BBE2. + bool dominates(const BasicBlockEdge &BBE1, const BasicBlockEdge &BBE2) const; // Ensure base class overloads are visible. using Base::isReachableFromEntry; Index: llvm/lib/IR/Dominators.cpp =================================================================== --- llvm/lib/IR/Dominators.cpp +++ llvm/lib/IR/Dominators.cpp @@ -316,6 +316,14 @@ return isReachableFromEntry(I->getParent()); } +// Edge BBE1 dominates edge BBE2 if they match or BBE1 dominates start of BBE2. +bool DominatorTree::dominates(const BasicBlockEdge &BBE1, + const BasicBlockEdge &BBE2) const { + if (BBE1.getStart() == BBE2.getStart() && BBE1.getEnd() == BBE2.getEnd()) + return true; + return dominates(BBE1, BBE2.getStart()); +} + //===----------------------------------------------------------------------===// // DominatorTreeAnalysis and related pass implementations //===----------------------------------------------------------------------===// Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2713,6 +2713,75 @@ return false; } +static Value *SimplifyUsingControlFlow(InstCombiner &Self, PHINode &PN, + const DominatorTree &DT) { + // Simplify the following patterns: + // if (cond) + // / \ + // ... ... + // \ / + // phi [true] [false] + if (!PN.getType()->isIntegerTy(1)) + return nullptr; + + if (PN.getNumOperands() != 2) + return nullptr; + + // Make sure all inputs are constants. + if (!all_of(PN.operands(), [](Value *V) { return isa(V); })) + return nullptr; + + BasicBlock *BB = PN.getParent(); + // Do not bother with unreachable instructions. + if (!DT.isReachableFromEntry(BB)) + return nullptr; + + // Same inputs. + if (PN.getOperand(0) == PN.getOperand(1)) + return PN.getOperand(0); + + BasicBlock *TruePred = nullptr, *FalsePred = nullptr; + for (auto *Pred : predecessors(BB)) { + auto *Input = cast(PN.getIncomingValueForBlock(Pred)); + if (Input->isAllOnesValue()) + TruePred = Pred; + else + FalsePred = Pred; + } + assert(TruePred && FalsePred && "Must be!"); + + // Check which edge of the dominator dominates the true input. If it is the + // false edge, we should invert the condition. + auto *IDom = DT.getNode(BB)->getIDom()->getBlock(); + auto *BI = dyn_cast(IDom->getTerminator()); + if (!BI || BI->isUnconditional()) + return nullptr; + + // Check that edges outgoing from the idom's terminators dominate respective + // inputs of the Phi. + BasicBlockEdge TrueOutEdge(IDom, BI->getSuccessor(0)); + BasicBlockEdge FalseOutEdge(IDom, BI->getSuccessor(1)); + + BasicBlockEdge TrueIncEdge(TruePred, BB); + BasicBlockEdge FalseIncEdge(FalsePred, BB); + + auto *Cond = BI->getCondition(); + if (DT.dominates(TrueOutEdge, TrueIncEdge) && + DT.dominates(FalseOutEdge, FalseIncEdge)) + // This Phi is actually equivalent to branching condition of IDom. + return Cond; + else if (DT.dominates(TrueOutEdge, FalseIncEdge) && + DT.dominates(FalseOutEdge, TrueIncEdge)) { + // This Phi is actually opposite to branching condition of IDom. We invert + // the condition that will potentially open up some opportunities for + // sinking. + Self.Builder.SetInsertPoint(BB->getFirstNonPHI()); + return Self.Builder.CreateNot(Cond); + } + + return nullptr; +} + Instruction *InstCombiner::visitReturnInst(ReturnInst &RI) { if (RI.getNumOperands() == 0) // ret void return nullptr; @@ -2726,6 +2795,12 @@ if (isMustTailCall(ResultOp)) return nullptr; + // See if we can replace a Phi with constant inputs with condition of another + // dominating branch. + if (auto *PN = dyn_cast(ResultOp)) + if (Value *V = SimplifyUsingControlFlow(*this, *PN, DT)) + return replaceOperand(RI, 0, V); + // There might be assume intrinsics dominating this return that completely // determine the value. If so, constant fold it. KnownBits Known = computeKnownBits(ResultOp, 0, &RI); @@ -2770,6 +2845,12 @@ return &BI; } + // See if we can replace a Phi with constant inputs with condition of another + // dominating branch. + if (auto *PN = dyn_cast(BI.getCondition())) + if (Value *V = SimplifyUsingControlFlow(*this, *PN, DT)) + return replaceOperand(BI, 0, V); + return nullptr; } Index: llvm/test/Transforms/InstCombine/branch.ll =================================================================== --- llvm/test/Transforms/InstCombine/branch.ll +++ llvm/test/Transforms/InstCombine/branch.ll @@ -32,7 +32,6 @@ ret i32 %x } -; TODO: Simplify this to "ret cond". define i1 @test01(i1 %cond) { ; CHECK-LABEL: @test01( ; CHECK-NEXT: entry: @@ -42,15 +41,13 @@ ; CHECK: if.false.1: ; CHECK-NEXT: br label [[MERGE_1]] ; CHECK: merge.1: -; CHECK-NEXT: [[MERGE_COND_1:%.*]] = phi i1 [ true, [[IF_TRUE_1]] ], [ false, [[IF_FALSE_1]] ] -; CHECK-NEXT: br i1 [[MERGE_COND_1]], label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]] ; CHECK: if.true.2: ; CHECK-NEXT: br label [[MERGE_2:%.*]] ; CHECK: if.false.2: ; CHECK-NEXT: br label [[MERGE_2]] ; CHECK: merge.2: -; CHECK-NEXT: [[MERGE_COND_2:%.*]] = phi i1 [ true, [[IF_TRUE_2]] ], [ false, [[IF_FALSE_2]] ] -; CHECK-NEXT: ret i1 [[MERGE_COND_2]] +; CHECK-NEXT: ret i1 [[COND]] ; entry: br i1 %cond, label %if.true.1, label %if.false.1 @@ -76,7 +73,6 @@ ret i1 %merge.cond.2 } -; TODO: Simplify this to "ret %cond". define i1 @test02(i1 %cond) { ; CHECK-LABEL: @test02( ; CHECK-NEXT: entry: @@ -86,15 +82,13 @@ ; CHECK: if.false.1: ; CHECK-NEXT: br label [[MERGE_1]] ; CHECK: merge.1: -; CHECK-NEXT: [[MERGE_COND_1:%.*]] = phi i1 [ false, [[IF_TRUE_1]] ], [ true, [[IF_FALSE_1]] ] -; CHECK-NEXT: br i1 [[MERGE_COND_1]], label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]] +; CHECK-NEXT: br i1 [[COND]], label [[IF_FALSE_2:%.*]], label [[IF_TRUE_2:%.*]] ; CHECK: if.true.2: ; CHECK-NEXT: br label [[MERGE_2:%.*]] ; CHECK: if.false.2: ; CHECK-NEXT: br label [[MERGE_2]] ; CHECK: merge.2: -; CHECK-NEXT: [[MERGE_COND_2:%.*]] = phi i1 [ false, [[IF_TRUE_2]] ], [ true, [[IF_FALSE_2]] ] -; CHECK-NEXT: ret i1 [[MERGE_COND_2]] +; CHECK-NEXT: ret i1 [[COND]] ; entry: br i1 %cond, label %if.true.1, label %if.false.1 Index: llvm/test/Transforms/InstCombine/simple_phi_condition.ll =================================================================== --- llvm/test/Transforms/InstCombine/simple_phi_condition.ll +++ llvm/test/Transforms/InstCombine/simple_phi_condition.ll @@ -12,8 +12,7 @@ ; CHECK: if.false: ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: -; CHECK-NEXT: [[RET:%.*]] = phi i1 [ true, [[IF_TRUE]] ], [ false, [[IF_FALSE]] ] -; CHECK-NEXT: ret i1 [[RET]] +; CHECK-NEXT: ret i1 [[COND]] ; entry: br i1 %cond, label %if.true, label %if.false @@ -39,8 +38,8 @@ ; CHECK: if.false: ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: -; CHECK-NEXT: [[RET:%.*]] = phi i1 [ false, [[IF_TRUE]] ], [ true, [[IF_FALSE]] ] -; CHECK-NEXT: ret i1 [[RET]] +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND]], true +; CHECK-NEXT: ret i1 [[TMP0]] ; entry: br i1 %cond, label %if.true, label %if.false @@ -73,8 +72,7 @@ ; CHECK: if.false: ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: -; CHECK-NEXT: [[RET:%.*]] = phi i1 [ true, [[IF_TRUE_END]] ], [ false, [[IF_FALSE]] ] -; CHECK-NEXT: ret i1 [[RET]] +; CHECK-NEXT: ret i1 [[COND]] ; entry: br i1 %cond, label %if.true, label %if.false @@ -116,8 +114,8 @@ ; CHECK: if.false: ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: -; CHECK-NEXT: [[RET:%.*]] = phi i1 [ false, [[IF_TRUE_END]] ], [ true, [[IF_FALSE]] ] -; CHECK-NEXT: ret i1 [[RET]] +; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND]], true +; CHECK-NEXT: ret i1 [[TMP0]] ; entry: br i1 %cond, label %if.true, label %if.false