[llvm] 0047206 - [InstCombine] Simplify boolean Phis with const inputs using CFG
Max Kazantsev via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 22:12:22 PDT 2020
Author: Max Kazantsev
Date: 2020-07-16T12:06:10+07:00
New Revision: 00472067c34ccbceb2fad4b905524f3c780bb7d5
URL: https://github.com/llvm/llvm-project/commit/00472067c34ccbceb2fad4b905524f3c780bb7d5
DIFF: https://github.com/llvm/llvm-project/commit/00472067c34ccbceb2fad4b905524f3c780bb7d5.diff
LOG: [InstCombine] Simplify boolean Phis with const inputs using CFG
This patch adds simplification for pattern:
```
if (cond)
/ \
... ...
\ /
p = phi [true] [false]
...
br p, succ_1, succ_2
```
If we can prove that top block's branches dominate respective
inputs of a block that has a Phi with constant inputs, we can
use the branch condition (maybe inverted) instead of Phi.
This will make proofs of implication for further jump threading
more transparent.
Differential Revision: https://reviews.llvm.org/D81375
Reviewed By: xbolva00
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
llvm/test/Transforms/CallSiteSplitting/callsite-split.ll
llvm/test/Transforms/InstCombine/branch.ll
llvm/test/Transforms/InstCombine/icmp-constant-phi.ll
llvm/test/Transforms/InstCombine/phi.ll
llvm/test/Transforms/InstCombine/select.ll
llvm/test/Transforms/InstCombine/simple_phi_condition.ll
llvm/test/Transforms/PhaseOrdering/simplifycfg-options.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index 2b2f2e1b9470..30f12d60f4c2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -1129,6 +1129,75 @@ Instruction *InstCombiner::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) {
return replaceInstUsesWith(FirstPhi, Undef);
}
+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<ConstantInt>(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<ConstantInt>(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<BranchInst>(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;
+}
+
// PHINode simplification
//
Instruction *InstCombiner::visitPHINode(PHINode &PN) {
@@ -1276,5 +1345,9 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) {
if (Instruction *Res = SliceUpIllegalIntegerPHI(PN))
return Res;
+ // Ultimately, try to replace this Phi with a dominating condition.
+ if (auto *V = SimplifyUsingControlFlow(*this, PN, DT))
+ return replaceInstUsesWith(PN, V);
+
return nullptr;
}
diff --git a/llvm/test/Transforms/CallSiteSplitting/callsite-split.ll b/llvm/test/Transforms/CallSiteSplitting/callsite-split.ll
index 117464904ceb..4147720dcb45 100644
--- a/llvm/test/Transforms/CallSiteSplitting/callsite-split.ll
+++ b/llvm/test/Transforms/CallSiteSplitting/callsite-split.ll
@@ -74,8 +74,8 @@ declare void @dummy1(%struct.bitmap*, %struct.bitmap*, %struct.bitmap*, %struct.
;CHECK-LABEL: NextCond.split:
;CHECK: call void @dummy3()
;CheCK-LABEL: CallSiteBB:
-;CHECK: %phi.call = phi i1 [ true, %NextCond.split ], [ false, %Top.split ]
-;CHECK: call void @foo(i1 %phi.call)
+;CHECK: [[NEG:%.*]] = xor i1 %tobool1, true
+;CHECK: call void @foo(i1 [[NEG]])
define void @caller2(i1 %c, %struct.bitmap* %a_elt, %struct.bitmap* %b_elt, %struct.bitmap* %c_elt) {
entry:
br label %Top
diff --git a/llvm/test/Transforms/InstCombine/branch.ll b/llvm/test/Transforms/InstCombine/branch.ll
index 4e271725d53a..af87d238c9da 100644
--- a/llvm/test/Transforms/InstCombine/branch.ll
+++ b/llvm/test/Transforms/InstCombine/branch.ll
@@ -32,7 +32,6 @@ patatino:
ret i32 %x
}
-; TODO: Simplify this to "ret cond".
define i1 @test01(i1 %cond) {
; CHECK-LABEL: @test01(
; CHECK-NEXT: entry:
@@ -42,15 +41,13 @@ define i1 @test01(i1 %cond) {
; 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 @@ merge.2:
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 @@ define i1 @test02(i1 %cond) {
; 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
diff --git a/llvm/test/Transforms/InstCombine/icmp-constant-phi.ll b/llvm/test/Transforms/InstCombine/icmp-constant-phi.ll
index 7d4b9294143f..d87ed5e6192a 100644
--- a/llvm/test/Transforms/InstCombine/icmp-constant-phi.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-constant-phi.ll
@@ -11,10 +11,10 @@ define i1 @test_eq(i1 %cond) {
; CHECK: if.false:
; CHECK-NEXT: br label [[MERGE]]
; CHECK: merge:
-; CHECK-NEXT: [[COMPARE:%.*]] = phi i1 [ true, [[IF_FALSE]] ], [ false, [[IF_TRUE]] ]
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
-; CHECK-NEXT: ret i1 [[COMPARE]]
+; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[COND]], true
+; CHECK-NEXT: ret i1 [[TMP0]]
;
entry:
br i1 %cond, label %if.true, label %if.false
@@ -43,10 +43,9 @@ define i1 @test_slt(i1 %cond) {
; CHECK: if.false:
; CHECK-NEXT: br label [[MERGE]]
; CHECK: merge:
-; CHECK-NEXT: [[COMPARE:%.*]] = phi i1 [ false, [[IF_FALSE]] ], [ true, [[IF_TRUE]] ]
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
-; CHECK-NEXT: ret i1 [[COMPARE]]
+; CHECK-NEXT: ret i1 [[COND]]
;
entry:
br i1 %cond, label %if.true, label %if.false
@@ -106,10 +105,9 @@ define i1 @test_ne(i1 %cond) {
; CHECK: if.false:
; CHECK-NEXT: br label [[MERGE]]
; CHECK: merge:
-; CHECK-NEXT: [[COMPARE:%.*]] = phi i1 [ false, [[IF_FALSE]] ], [ true, [[IF_TRUE]] ]
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: exit:
-; CHECK-NEXT: ret i1 [[COMPARE]]
+; CHECK-NEXT: ret i1 [[COND]]
;
entry:
br i1 %cond, label %if.true, label %if.false
diff --git a/llvm/test/Transforms/InstCombine/phi.ll b/llvm/test/Transforms/InstCombine/phi.ll
index d2e028534d87..7c3f3102e0bc 100644
--- a/llvm/test/Transforms/InstCombine/phi.ll
+++ b/llvm/test/Transforms/InstCombine/phi.ll
@@ -416,10 +416,11 @@ bb1: ; preds = %entry
bb2: ; preds = %bb1, %entry
%cond = phi i1 [ true, %bb1 ], [ false, %entry ] ; <i1> [#uses=1]
-; CHECK-NOT: %val = phi i32 [ %0, %bb1 ], [ 0, %entry ]
+; CHECK-NOT: phi i1
+; CHECK: %res = phi i32 [ %0, %bb1 ], [ 0, %entry ]
+; CHECK: ret i32 %res
%val = phi i32 [ %0, %bb1 ], [ 0, %entry ] ; <i32> [#uses=1]
%res = select i1 %cond, i32 %val, i32 0 ; <i32> [#uses=1]
-; CHECK: ret i32 %cond
ret i32 %res
}
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 8cd0e35139a8..1f16f92d83a6 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -448,8 +448,8 @@ define i32 @test25(i1 %c) {
; CHECK: jump:
; CHECK-NEXT: br label [[RET]]
; CHECK: ret:
-; CHECK-NEXT: [[A:%.*]] = phi i32 [ 10, [[JUMP]] ], [ 20, [[ENTRY:%.*]] ]
-; CHECK-NEXT: ret i32 [[A]]
+; CHECK-NEXT: [[B:%.*]] = phi i32 [ 10, [[JUMP]] ], [ 20, [[ENTRY:%.*]] ]
+; CHECK-NEXT: ret i32 [[B]]
;
entry:
br i1 %c, label %jump, label %ret
@@ -468,8 +468,8 @@ define i32 @test26(i1 %cond) {
; CHECK: jump:
; CHECK-NEXT: br label [[RET]]
; CHECK: ret:
-; CHECK-NEXT: [[A:%.*]] = phi i32 [ 20, [[ENTRY:%.*]] ], [ 10, [[JUMP]] ]
-; CHECK-NEXT: ret i32 [[A]]
+; CHECK-NEXT: [[B:%.*]] = phi i32 [ 10, [[JUMP]] ], [ 20, [[ENTRY:%.*]] ]
+; CHECK-NEXT: ret i32 [[B]]
;
entry:
br i1 %cond, label %jump, label %ret
@@ -489,8 +489,8 @@ define i32 @test27(i1 %c, i32 %A, i32 %B) {
; CHECK: jump:
; CHECK-NEXT: br label [[RET]]
; CHECK: ret:
-; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
-; CHECK-NEXT: ret i32 [[P]]
+; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: ret i32 [[S]]
;
entry:
br i1 %c, label %jump, label %ret
@@ -509,8 +509,8 @@ define i32 @test28(i1 %cond, i32 %A, i32 %B) {
; CHECK: jump:
; CHECK-NEXT: br label [[RET]]
; CHECK: ret:
-; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
-; CHECK-NEXT: ret i32 [[P]]
+; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: ret i32 [[S]]
;
entry:
br i1 %cond, label %jump, label %ret
@@ -530,10 +530,10 @@ define i32 @test29(i1 %cond, i32 %A, i32 %B) {
; CHECK: jump:
; CHECK-NEXT: br label [[RET]]
; CHECK: ret:
-; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[S:%.*]] = phi i32 [ [[A:%.*]], [[JUMP]] ], [ [[B:%.*]], [[ENTRY:%.*]] ]
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
-; CHECK-NEXT: ret i32 [[P]]
+; CHECK-NEXT: ret i32 [[S]]
;
entry:
br i1 %cond, label %jump, label %ret
diff --git a/llvm/test/Transforms/InstCombine/simple_phi_condition.ll b/llvm/test/Transforms/InstCombine/simple_phi_condition.ll
index cded618fba16..37f7fe77b7e3 100644
--- a/llvm/test/Transforms/InstCombine/simple_phi_condition.ll
+++ b/llvm/test/Transforms/InstCombine/simple_phi_condition.ll
@@ -2,7 +2,6 @@
; RUN: opt -S < %s -instcombine | FileCheck %s
; RUN: opt -S < %s -passes=instcombine | FileCheck %s
-; TODO: Simplify to "ret cond".
define i1 @test_direct_implication(i1 %cond) {
; CHECK-LABEL: @test_direct_implication(
; CHECK-NEXT: entry:
@@ -12,8 +11,7 @@ define i1 @test_direct_implication(i1 %cond) {
; 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
@@ -29,7 +27,6 @@ merge:
ret i1 %ret
}
-; TODO: Simplify to "ret !cond".
define i1 @test_inverted_implication(i1 %cond) {
; CHECK-LABEL: @test_inverted_implication(
; CHECK-NEXT: entry:
@@ -39,8 +36,8 @@ define i1 @test_inverted_implication(i1 %cond) {
; 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
@@ -56,7 +53,6 @@ merge:
ret i1 %ret
}
-; TODO: Simplify to "ret cond".
define i1 @test_direct_implication_complex_cfg(i1 %cond, i32 %cnt1) {
; CHECK-LABEL: @test_direct_implication_complex_cfg(
; CHECK-NEXT: entry:
@@ -73,8 +69,7 @@ define i1 @test_direct_implication_complex_cfg(i1 %cond, i32 %cnt1) {
; 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
@@ -99,7 +94,6 @@ merge:
ret i1 %ret
}
-; TODO: Simplify to "ret !cond".
define i1 @test_inverted_implication_complex_cfg(i1 %cond, i32 %cnt1) {
; CHECK-LABEL: @test_inverted_implication_complex_cfg(
; CHECK-NEXT: entry:
@@ -116,8 +110,8 @@ define i1 @test_inverted_implication_complex_cfg(i1 %cond, i32 %cnt1) {
; 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
diff --git a/llvm/test/Transforms/PhaseOrdering/simplifycfg-options.ll b/llvm/test/Transforms/PhaseOrdering/simplifycfg-options.ll
index 6b3ba66c951e..0115c6834277 100644
--- a/llvm/test/Transforms/PhaseOrdering/simplifycfg-options.ll
+++ b/llvm/test/Transforms/PhaseOrdering/simplifycfg-options.ll
@@ -18,16 +18,16 @@ define i1 @PR33605(i32 %a, i32 %b, i32* %c) {
; ALL-NEXT: call void @foo()
; ALL-NEXT: br label [[IF_END]]
; ALL: if.end:
-; ALL-NEXT: [[CHANGED_1_OFF0:%.*]] = phi i1 [ true, [[IF_THEN]] ], [ false, [[ENTRY:%.*]] ]
-; ALL-NEXT: [[TMP1:%.*]] = load i32, i32* [[C]], align 4
-; ALL-NEXT: [[CMP_1:%.*]] = icmp eq i32 [[OR]], [[TMP1]]
+; ALL-NEXT: [[TMP1:%.*]] = xor i1 [[CMP]], true
+; ALL-NEXT: [[TMP2:%.*]] = load i32, i32* [[C]], align 4
+; ALL-NEXT: [[CMP_1:%.*]] = icmp eq i32 [[OR]], [[TMP2]]
; ALL-NEXT: br i1 [[CMP_1]], label [[IF_END_1:%.*]], label [[IF_THEN_1:%.*]]
; ALL: if.then.1:
; ALL-NEXT: store i32 [[OR]], i32* [[C]], align 4
; ALL-NEXT: call void @foo()
; ALL-NEXT: br label [[IF_END_1]]
; ALL: if.end.1:
-; ALL-NEXT: [[CHANGED_1_OFF0_1:%.*]] = phi i1 [ true, [[IF_THEN_1]] ], [ [[CHANGED_1_OFF0]], [[IF_END]] ]
+; ALL-NEXT: [[CHANGED_1_OFF0_1:%.*]] = phi i1 [ true, [[IF_THEN_1]] ], [ [[TMP1]], [[IF_END]] ]
; ALL-NEXT: ret i1 [[CHANGED_1_OFF0_1]]
;
entry:
More information about the llvm-commits
mailing list