[llvm] e808cab - [InstCombine] Improve select -> phi canonicalization: consider more blocks
Max Kazantsev via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 12 21:40:53 PDT 2020
Author: Max Kazantsev
Date: 2020-07-13T11:40:32+07:00
New Revision: e808cab824488af137b62902e65dec3827b83b46
URL: https://github.com/llvm/llvm-project/commit/e808cab824488af137b62902e65dec3827b83b46
DIFF: https://github.com/llvm/llvm-project/commit/e808cab824488af137b62902e65dec3827b83b46.diff
LOG: [InstCombine] Improve select -> phi canonicalization: consider more blocks
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
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
llvm/test/Transforms/InstCombine/select.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 233fb3878ba7..17124f717af7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -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;
@@ -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();
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index f990a58f984c..08e547a6ea0a 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -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
@@ -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
More information about the llvm-commits
mailing list