Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2443,6 +2443,59 @@ return nullptr; } +static Instruction *foldSelectToPhi(SelectInst &Sel, const DominatorTree &DT, + InstCombiner::BuilderTy &Builder) { + // Find the block's immediate dominator that ends with a conditional branch + // that matches select's condition (maybe inverted). + BasicBlock *BB = Sel.getParent(); + auto *IDomNode = DT[BB]->getIDom(); + if (!IDomNode) + return nullptr; + BasicBlock *IDom = IDomNode->getBlock(); + + Value *Cond = Sel.getCondition(); + Value *IfTrue, *IfFalse; + BasicBlock *TrueSucc, *FalseSucc; + if (match(IDom->getTerminator(), + m_Br(m_Specific(Cond), m_BasicBlock(TrueSucc), + m_BasicBlock(FalseSucc)))) { + IfTrue = Sel.getTrueValue(); + IfFalse = Sel.getFalseValue(); + } else if (match(IDom->getTerminator(), + m_Br(m_Not(m_Specific(Cond)), m_BasicBlock(TrueSucc), + m_BasicBlock(FalseSucc)))) { + IfTrue = Sel.getFalseValue(); + IfFalse = Sel.getTrueValue(); + } else + return nullptr; + + BasicBlockEdge TrueEdge(IDom, TrueSucc); + BasicBlockEdge FalseEdge(IDom, FalseSucc); + DenseMap Inputs; + for (auto *Pred : predecessors(BB)) { + // Check implication. + BasicBlockEdge Incoming(Pred, BB); + if (DT.dominates(TrueEdge, Incoming)) + Inputs[Pred] = IfTrue; + else if (DT.dominates(FalseEdge, Incoming)) + Inputs[Pred] = IfFalse; + else + return nullptr; + // Check availability. + if (auto *Insn = dyn_cast(Inputs[Pred])) + if (!DT.dominates(Insn, Pred->getTerminator())) + return nullptr; + } + + Builder.SetInsertPoint(&*BB->begin()); + auto *PN = Builder.CreatePHI(Sel.getType(), Inputs.size()); + for (auto *Pred : predecessors(BB)) { + PN->addIncoming(Inputs[Pred], Pred); + } + PN->takeName(&Sel); + return PN; +} + Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { Value *CondVal = SI.getCondition(); Value *TrueVal = SI.getTrueValue(); @@ -2904,5 +2957,8 @@ if (Instruction *Copysign = foldSelectToCopysign(SI, Builder)) return Copysign; + if (Instruction *PN = foldSelectToPhi(SI, DT, Builder)) + return replaceInstUsesWith(SI, PN); + return nullptr; } Index: llvm/test/Transforms/InstCombine/select.ll =================================================================== --- llvm/test/Transforms/InstCombine/select.ll +++ llvm/test/Transforms/InstCombine/select.ll @@ -1670,7 +1670,6 @@ ret float %r } -; TODO: we can replace select with a Phi. define i32 @select_dominating_cond(i1 %cond, i32 %x, i32 %y) { ; CHECK-LABEL: @select_dominating_cond( ; CHECK-NEXT: entry: @@ -1680,7 +1679,7 @@ ; CHECK: if.false: ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: -; CHECK-NEXT: [[S:%.*]] = select i1 [[COND]], i32 [[X:%.*]], i32 [[Y:%.*]] +; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[Y:%.*]], [[IF_FALSE]] ], [ [[X:%.*]], [[IF_TRUE]] ] ; CHECK-NEXT: ret i32 [[S]] ; entry: @@ -1697,6 +1696,33 @@ ret i32 %s } +define i32 @select_dominating_inverted(i1 %cond, i32 %x, i32 %y) { +; CHECK-LABEL: @select_dominating_inverted( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_FALSE:%.*]], label [[IF_TRUE:%.*]] +; CHECK: if.true: +; CHECK-NEXT: br label [[MERGE:%.*]] +; CHECK: if.false: +; CHECK-NEXT: br label [[MERGE]] +; CHECK: merge: +; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[X:%.*]], [[IF_FALSE]] ], [ [[Y:%.*]], [[IF_TRUE]] ] +; CHECK-NEXT: ret i32 [[S]] +; +entry: + %inverted = xor i1 %cond, 1 + br i1 %inverted, label %if.true, label %if.false + +if.true: + br label %merge + +if.false: + br label %merge + +merge: + %s = select i1 %cond, i32 %x, i32 %y + ret i32 %s +} + ; TODO: We can replace select with a Phi and then sink a and b to respective ; branches. define i32 @select_dominating_cond_and_sink(i1 %cond, i32 %x, i32 %y) {