diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2443,11 +2443,11 @@ return nullptr; } -static Instruction *foldSelectToPhi(SelectInst &Sel, const DominatorTree &DT, - InstCombiner::BuilderTy &Builder) { +static Instruction *foldSelectToPhiImpl(SelectInst &Sel, BasicBlock *BB, + 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; @@ -2500,6 +2500,21 @@ return PN; } +static Instruction *foldSelectToPhi(SelectInst &Sel, const DominatorTree &DT, + InstCombiner::BuilderTy &Builder) { + // Try to replace this select with Phi in one of these blocks. + SmallSetVector CandidateBlocks; + CandidateBlocks.insert(Sel.getParent()); + for (Value *V : Sel.operands()) + if (auto *I = dyn_cast(V)) + CandidateBlocks.insert(I->getParent()); + + for (BasicBlock *BB : CandidateBlocks) + if (auto *PN = foldSelectToPhiImpl(Sel, BB, DT, Builder)) + return PN; + return nullptr; +} + Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { Value *CondVal = SI.getCondition(); Value *TrueVal = SI.getTrueValue(); diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll --- a/llvm/test/Transforms/InstCombine/select.ll +++ b/llvm/test/Transforms/InstCombine/select.ll @@ -2250,11 +2250,40 @@ ; CHECK: if.false: ; CHECK-NEXT: br label [[MERGE]] ; CHECK: merge: -; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[A:%.*]], [[IF_TRUE]] ], [ [[B:%.*]], [[IF_FALSE]] ] ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: exit: -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], i32 [[PHI]], i32 [[A]] -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: ret i32 [[A:%.*]] +; +entry: + br i1 %cond, label %if.true, label %if.false + +if.true: + br label %merge + +if.false: + br label %merge + +merge: + %phi = phi i32 [%A, %if.true], [%B, %if.false] + br label %exit + +exit: + %sel = select i1 %cond, i32 %phi, i32 %A + ret i32 %sel +} + +define i32 @test_select_into_phi_not_idom_2(i1 %cond, i32 %A, i32 %B) { +; CHECK-LABEL: @test_select_into_phi_not_idom_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] +; CHECK: if.true: +; CHECK-NEXT: br label [[MERGE:%.*]] +; CHECK: if.false: +; CHECK-NEXT: br label [[MERGE]] +; CHECK: merge: +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[B:%.*]] ; entry: br i1 %cond, label %if.true, label %if.false @@ -2269,11 +2298,145 @@ %phi = phi i32 [%A, %if.true], [%B, %if.false] br label %exit +exit: + %sel = select i1 %cond, i32 %B, i32 %phi + ret i32 %sel +} + +define i32 @test_select_into_phi_not_idom_inverted(i1 %cond, i32 %A, i32 %B) { +; CHECK-LABEL: @test_select_into_phi_not_idom_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: [[SEL:%.*]] = phi i32 [ [[B:%.*]], [[IF_FALSE]] ], [ [[A:%.*]], [[IF_TRUE]] ] +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[SEL]] +; +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: + %phi = phi i32 [%A, %if.true], [%B, %if.false] + br label %exit + +exit: + %sel = select i1 %cond, i32 %phi, i32 %A + ret i32 %sel +} + +define i32 @test_select_into_phi_not_idom_inverted_2(i1 %cond, i32 %A, i32 %B) { +; CHECK-LABEL: @test_select_into_phi_not_idom_inverted_2( +; 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: [[SEL:%.*]] = phi i32 [ [[B:%.*]], [[IF_FALSE]] ], [ [[A:%.*]], [[IF_TRUE]] ] +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[SEL]] +; +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: + %phi = phi i32 [%A, %if.true], [%B, %if.false] + br label %exit + +exit: + %sel = select i1 %cond, i32 %B, i32 %phi + ret i32 %sel +} + +define i32 @test_select_into_phi_not_idom_no_dom_input_1(i1 %cond, i32 %A, i32 %B, i32 *%p) { +; CHECK-LABEL: @test_select_into_phi_not_idom_no_dom_input_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] +; CHECK: if.true: +; CHECK-NEXT: [[C:%.*]] = load i32, i32* [[P:%.*]], align 4 +; CHECK-NEXT: br label [[MERGE:%.*]] +; CHECK: if.false: +; CHECK-NEXT: br label [[MERGE]] +; CHECK: merge: +; CHECK-NEXT: [[SEL:%.*]] = phi i32 [ [[A:%.*]], [[IF_FALSE]] ], [ [[C]], [[IF_TRUE]] ] +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[SEL]] +; +entry: + br i1 %cond, label %if.true, label %if.false + +if.true: + %C = load i32, i32* %p + br label %merge + +if.false: + br label %merge + +merge: + %phi = phi i32 [%C, %if.true], [%B, %if.false] + br label %exit + exit: %sel = select i1 %cond, i32 %phi, i32 %A ret i32 %sel } +define i32 @test_select_into_phi_not_idom_no_dom_input_2(i1 %cond, i32 %A, i32 %B, i32 *%p) { +; CHECK-LABEL: @test_select_into_phi_not_idom_no_dom_input_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] +; CHECK: if.true: +; CHECK-NEXT: br label [[MERGE:%.*]] +; CHECK: if.false: +; CHECK-NEXT: [[C:%.*]] = load i32, i32* [[P:%.*]], align 4 +; CHECK-NEXT: br label [[MERGE]] +; CHECK: merge: +; CHECK-NEXT: [[SEL:%.*]] = phi i32 [ [[C]], [[IF_FALSE]] ], [ [[B:%.*]], [[IF_TRUE]] ] +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[SEL]] +; +entry: + br i1 %cond, label %if.true, label %if.false + +if.true: + br label %merge + +if.false: + %C = load i32, i32* %p + br label %merge + +merge: + %phi = phi i32 [%A, %if.true], [%C, %if.false] + br label %exit + +exit: + %sel = select i1 %cond, i32 %B, i32 %phi + ret i32 %sel +} + ; Negative tests to ensure we don't remove selects with undef true/false values. ; See https://bugs.llvm.org/show_bug.cgi?id=31633 ; https://lists.llvm.org/pipermail/llvm-dev/2016-October/106182.html