Skip to content

Commit

Permalink
[InstCombine] Improve select -> phi canonicalization: consider more b…
Browse files Browse the repository at this point in the history
…locks

We can try to replace select with a Phi not in its parent block alone,
but also in blocks of its arguments. We benefit from it when select's
argument is a Phi.

Differential Revision: https://reviews.llvm.org/D83284
Reviewed By: nikic
  • Loading branch information
xortator committed Jul 13, 2020
1 parent ac8dc52 commit e808cab
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 6 deletions.
21 changes: 18 additions & 3 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Expand Up @@ -2443,11 +2443,11 @@ Instruction *InstCombiner::foldVectorSelect(SelectInst &Sel) {
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;
Expand Down Expand Up @@ -2500,6 +2500,21 @@ static Instruction *foldSelectToPhi(SelectInst &Sel, const DominatorTree &DT,
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<BasicBlock *, 4> CandidateBlocks;
CandidateBlocks.insert(Sel.getParent());
for (Value *V : Sel.operands())
if (auto *I = dyn_cast<Instruction>(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();
Expand Down
169 changes: 166 additions & 3 deletions llvm/test/Transforms/InstCombine/select.ll
Expand Up @@ -2250,11 +2250,40 @@ define i32 @test_select_into_phi_not_idom(i1 %cond, i32 %A, i32 %B) {
; 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
Expand All @@ -2269,11 +2298,145 @@ 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_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
Expand Down

0 comments on commit e808cab

Please sign in to comment.