[llvm] [SimplifyCFG] Reland transform for redirecting phis between unmergeable BB and SuccBB (PR #68473)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 28 01:25:49 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-arm
Author: XChy (XChy)
<details>
<summary>Changes</summary>
Reland #<!-- -->67275 and try to fix bugs brought or exposed by #<!-- -->67275.
---
Patch is 38.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/68473.diff
7 Files Affected:
- (modified) llvm/lib/Transforms/Utils/Local.cpp (+128-38)
- (modified) llvm/test/CodeGen/ARM/jump-table-islands.ll (+4)
- (modified) llvm/test/Transforms/JumpThreading/codesize-loop.ll (+21-27)
- (modified) llvm/test/Transforms/SimplifyCFG/branch-fold.ll (+32)
- (added) llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll (+327)
- (modified) llvm/test/Transforms/SimplifyCFG/multiple-phis.ll (+274-5)
- (modified) llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll (+3)
``````````diff
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index ddb47e693a643d8..47382fefa206aa9 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -847,17 +847,17 @@ static bool CanMergeValues(Value *First, Value *Second) {
/// branch to Succ, into Succ.
///
/// Assumption: Succ is the single successor for BB.
-static bool CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
+static bool
+CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ,
+ const SmallPtrSetImpl<BasicBlock *> &BBPreds) {
assert(*succ_begin(BB) == Succ && "Succ is not successor of BB!");
LLVM_DEBUG(dbgs() << "Looking to fold " << BB->getName() << " into "
<< Succ->getName() << "\n");
// Shortcut, if there is only a single predecessor it must be BB and merging
// is always safe
- if (Succ->getSinglePredecessor()) return true;
-
- // Make a list of the predecessors of BB
- SmallPtrSet<BasicBlock*, 16> BBPreds(pred_begin(BB), pred_end(BB));
+ if (Succ->getSinglePredecessor())
+ return true;
// Look at all the phi nodes in Succ, to see if they present a conflict when
// merging these blocks
@@ -997,6 +997,35 @@ static void replaceUndefValuesInPhi(PHINode *PN,
}
}
+// Only when they shares a single common predecessor, return true.
+// Only handles cases when BB can't be merged while its predecessors can be
+// redirected.
+static bool
+CanRedirectPredsOfEmptyBBToSucc(BasicBlock *BB, BasicBlock *Succ,
+ const SmallPtrSetImpl<BasicBlock *> &BBPreds,
+ const SmallPtrSetImpl<BasicBlock *> &SuccPreds,
+ BasicBlock *&CommonPred) {
+
+ // There must be phis in BB, otherwise BB will be merged into Succ directly
+ if (BB->phis().empty() || Succ->phis().empty())
+ return false;
+
+ // BB must have predecessors not shared that can be redirected to Succ
+ if (!BB->hasNPredecessorsOrMore(2))
+ return false;
+
+ // Get single common predecessors of both BB and Succ
+ for (BasicBlock *SuccPred : SuccPreds) {
+ if (BBPreds.count(SuccPred)) {
+ if (CommonPred)
+ return false;
+ CommonPred = SuccPred;
+ }
+ }
+
+ return true;
+}
+
/// Replace a value flowing from a block to a phi with
/// potentially multiple instances of that value flowing from the
/// block's predecessors to the phi.
@@ -1004,9 +1033,11 @@ static void replaceUndefValuesInPhi(PHINode *PN,
/// \param BB The block with the value flowing into the phi.
/// \param BBPreds The predecessors of BB.
/// \param PN The phi that we are updating.
+/// \param CommonPred The common predecessor of BB and PN's BasicBlock
static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
const PredBlockVector &BBPreds,
- PHINode *PN) {
+ PHINode *PN,
+ BasicBlock *CommonPred) {
Value *OldVal = PN->removeIncomingValue(BB, false);
assert(OldVal && "No entry in PHI for Pred BB!");
@@ -1034,26 +1065,39 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
// will trigger asserts if we try to clean it up now, without also
// simplifying the corresponding conditional branch).
BasicBlock *PredBB = OldValPN->getIncomingBlock(i);
+
+ if (PredBB == CommonPred)
+ continue;
+
Value *PredVal = OldValPN->getIncomingValue(i);
- Value *Selected = selectIncomingValueForBlock(PredVal, PredBB,
- IncomingValues);
+ Value *Selected =
+ selectIncomingValueForBlock(PredVal, PredBB, IncomingValues);
// And add a new incoming value for this predecessor for the
// newly retargeted branch.
PN->addIncoming(Selected, PredBB);
}
+ if (CommonPred)
+ PN->addIncoming(OldValPN->getIncomingValueForBlock(CommonPred), BB);
+
} else {
for (unsigned i = 0, e = BBPreds.size(); i != e; ++i) {
// Update existing incoming values in PN for this
// predecessor of BB.
BasicBlock *PredBB = BBPreds[i];
- Value *Selected = selectIncomingValueForBlock(OldVal, PredBB,
- IncomingValues);
+
+ if (PredBB == CommonPred)
+ continue;
+
+ Value *Selected =
+ selectIncomingValueForBlock(OldVal, PredBB, IncomingValues);
// And add a new incoming value for this predecessor for the
// newly retargeted branch.
PN->addIncoming(Selected, PredBB);
}
+ if (CommonPred)
+ PN->addIncoming(OldVal, BB);
}
replaceUndefValuesInPhi(PN, IncomingValues);
@@ -1064,13 +1108,30 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
assert(BB != &BB->getParent()->getEntryBlock() &&
"TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
- // We can't eliminate infinite loops.
+ // We can't simplify infinite loops.
BasicBlock *Succ = cast<BranchInst>(BB->getTerminator())->getSuccessor(0);
- if (BB == Succ) return false;
+ if (BB == Succ)
+ return false;
+
+ SmallPtrSet<BasicBlock *, 16> BBPreds(pred_begin(BB), pred_end(BB));
+ SmallPtrSet<BasicBlock *, 16> SuccPreds(pred_begin(Succ), pred_end(Succ));
- // Check to see if merging these blocks would cause conflicts for any of the
- // phi nodes in BB or Succ. If not, we can safely merge.
- if (!CanPropagatePredecessorsForPHIs(BB, Succ)) return false;
+ // The single common predecessor of BB and Succ when BB cannot be killed
+ BasicBlock *CommonPred = nullptr;
+
+ bool BBKillable = CanPropagatePredecessorsForPHIs(BB, Succ, BBPreds);
+
+ // Even if we can not fold bB into Succ, we may be able to redirect the
+ // predecessors of BB to Succ.
+ bool BBPhisMergeable =
+ BBKillable ||
+ CanRedirectPredsOfEmptyBBToSucc(BB, Succ, BBPreds, SuccPreds, CommonPred);
+
+ if (!BBKillable && !BBPhisMergeable)
+ return false;
+
+ // Check to see if merging these blocks/phis would cause conflicts for any of
+ // the phi nodes in BB or Succ. If not, we can safely merge.
// Check for cases where Succ has multiple predecessors and a PHI node in BB
// has uses which will not disappear when the PHI nodes are merged. It is
@@ -1099,6 +1160,11 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
}
}
+ if (BBPhisMergeable && CommonPred)
+ LLVM_DEBUG(dbgs() << "Found Common Predecessor between: " << BB->getName()
+ << " and " << Succ->getName() << " : "
+ << CommonPred->getName() << "\n");
+
// 'BB' and 'BB->Pred' are loop latches, bail out to presrve inner loop
// metadata.
//
@@ -1171,25 +1237,37 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
if (PredTI->hasMetadata(LLVMContext::MD_loop))
return false;
- LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
+ if (BBKillable)
+ LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
+ else if (BBPhisMergeable)
+ LLVM_DEBUG(dbgs() << "Merge Phis in Trivial BB: \n" << *BB);
SmallVector<DominatorTree::UpdateType, 32> Updates;
+
if (DTU) {
// To avoid processing the same predecessor more than once.
SmallPtrSet<BasicBlock *, 8> SeenPreds;
- // All predecessors of BB will be moved to Succ.
- SmallPtrSet<BasicBlock *, 8> PredsOfSucc(pred_begin(Succ), pred_end(Succ));
+ // All predecessors of BB (except the common predecessor) will be moved to
+ // Succ.
Updates.reserve(Updates.size() + 2 * pred_size(BB) + 1);
- for (auto *PredOfBB : predecessors(BB))
- // This predecessor of BB may already have Succ as a successor.
- if (!PredsOfSucc.contains(PredOfBB))
+
+ for (auto *PredOfBB : predecessors(BB)) {
+ // Do not modify those common predecessors of BB and Succ
+ if (!SuccPreds.contains(PredOfBB))
if (SeenPreds.insert(PredOfBB).second)
Updates.push_back({DominatorTree::Insert, PredOfBB, Succ});
+ }
+
SeenPreds.clear();
+
for (auto *PredOfBB : predecessors(BB))
- if (SeenPreds.insert(PredOfBB).second)
+ // When BB cannot be killed, do not remove the edge between BB and
+ // CommonPred.
+ if (SeenPreds.insert(PredOfBB).second && PredOfBB != CommonPred)
Updates.push_back({DominatorTree::Delete, PredOfBB, BB});
- Updates.push_back({DominatorTree::Delete, BB, Succ});
+
+ if (BBKillable)
+ Updates.push_back({DominatorTree::Delete, BB, Succ});
}
if (isa<PHINode>(Succ->begin())) {
@@ -1201,21 +1279,19 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
// Loop over all of the PHI nodes in the successor of BB.
for (BasicBlock::iterator I = Succ->begin(); isa<PHINode>(I); ++I) {
PHINode *PN = cast<PHINode>(I);
-
- redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN);
+ redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN, CommonPred);
}
}
if (Succ->getSinglePredecessor()) {
// BB is the only predecessor of Succ, so Succ will end up with exactly
// the same predecessors BB had.
-
// Copy over any phi, debug or lifetime instruction.
BB->getTerminator()->eraseFromParent();
Succ->splice(Succ->getFirstNonPHI()->getIterator(), BB);
} else {
while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
- // We explicitly check for such uses in CanPropagatePredecessorsForPHIs.
+ // We explicitly check for such uses for merging phis.
assert(PN->use_empty() && "There shouldn't be any uses here!");
PN->eraseFromParent();
}
@@ -1228,21 +1304,35 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
for (BasicBlock *Pred : predecessors(BB))
Pred->getTerminator()->setMetadata(LLVMContext::MD_loop, LoopMD);
- // Everything that jumped to BB now goes to Succ.
- BB->replaceAllUsesWith(Succ);
- if (!Succ->hasName()) Succ->takeName(BB);
-
- // Clear the successor list of BB to match updates applying to DTU later.
- if (BB->getTerminator())
- BB->back().eraseFromParent();
- new UnreachableInst(BB->getContext(), BB);
- assert(succ_empty(BB) && "The successor list of BB isn't empty before "
- "applying corresponding DTU updates.");
+ if (BBKillable) {
+ // Everything that jumped to BB now goes to Succ.
+ BB->replaceAllUsesWith(Succ);
+
+ if (!Succ->hasName())
+ Succ->takeName(BB);
+
+ // Clear the successor list of BB to match updates applying to DTU later.
+ if (BB->getTerminator())
+ BB->back().eraseFromParent();
+
+ new UnreachableInst(BB->getContext(), BB);
+ assert(succ_empty(BB) && "The successor list of BB isn't empty before "
+ "applying corresponding DTU updates.");
+ } else if (BBPhisMergeable) {
+ // Everything except CommonPred that jumped to BB now goes to Succ.
+ BB->replaceUsesWithIf(Succ, [BBPreds, CommonPred](Use &U) -> bool {
+ if (Instruction *UseInst = dyn_cast<Instruction>(U.getUser()))
+ return UseInst->getParent() != CommonPred &&
+ BBPreds.contains(UseInst->getParent());
+ return false;
+ });
+ }
if (DTU)
DTU->applyUpdates(Updates);
- DeleteDeadBlock(BB, DTU);
+ if (BBKillable)
+ DeleteDeadBlock(BB, DTU);
return true;
}
diff --git a/llvm/test/CodeGen/ARM/jump-table-islands.ll b/llvm/test/CodeGen/ARM/jump-table-islands.ll
index c327affc04539b3..e774930bd2bb0b9 100644
--- a/llvm/test/CodeGen/ARM/jump-table-islands.ll
+++ b/llvm/test/CodeGen/ARM/jump-table-islands.ll
@@ -2,6 +2,8 @@
%BigInt = type i8500
+declare void @use(%BigInt)
+
define %BigInt @test_moved_jumptable(i1 %tst, i32 %sw, %BigInt %l) {
; CHECK-LABEL: test_moved_jumptable:
@@ -34,6 +36,8 @@ other:
end:
%val = phi %BigInt [ %l, %complex ], [ -1, %simple ]
+; Prevent SimplifyCFG from simplifying the phi node above.
+ call void @use(%BigInt %val)
ret %BigInt %val
}
diff --git a/llvm/test/Transforms/JumpThreading/codesize-loop.ll b/llvm/test/Transforms/JumpThreading/codesize-loop.ll
index a1a2b1dfd15edb2..f01c149ac45a396 100644
--- a/llvm/test/Transforms/JumpThreading/codesize-loop.ll
+++ b/llvm/test/Transforms/JumpThreading/codesize-loop.ll
@@ -42,16 +42,14 @@ define i32 @test_minsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
; OVERIDE-NEXT: [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
; OVERIDE-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
; OVERIDE-NEXT: [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; OVERIDE-NEXT: br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; OVERIDE-NEXT: br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; OVERIDE: 5:
+; OVERIDE-NEXT: br label [[COND_END_THREAD]]
; OVERIDE: cond.end.thread:
-; OVERIDE-NEXT: [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; OVERIDE-NEXT: [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; OVERIDE-NEXT: br label [[TMP6]]
-; OVERIDE: 6:
-; OVERIDE-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; OVERIDE-NEXT: [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; OVERIDE-NEXT: [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; OVERIDE-NEXT: [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; OVERIDE-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; OVERIDE-NEXT: [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; OVERIDE-NEXT: [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; OVERIDE-NEXT: [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
; OVERIDE-NEXT: ret i32 0
;
entry:
@@ -90,16 +88,14 @@ define i32 @test_optsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
; DEFAULT-NEXT: [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
; DEFAULT-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
; DEFAULT-NEXT: [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; DEFAULT-NEXT: br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; DEFAULT-NEXT: br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; DEFAULT: 5:
+; DEFAULT-NEXT: br label [[COND_END_THREAD]]
; DEFAULT: cond.end.thread:
-; DEFAULT-NEXT: [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; DEFAULT-NEXT: [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; DEFAULT-NEXT: br label [[TMP6]]
-; DEFAULT: 6:
-; DEFAULT-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; DEFAULT-NEXT: [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; DEFAULT-NEXT: [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; DEFAULT-NEXT: [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; DEFAULT-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; DEFAULT-NEXT: [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; DEFAULT-NEXT: [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; DEFAULT-NEXT: [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
; DEFAULT-NEXT: ret i32 0
;
; OVERIDE-LABEL: @test_optsize(
@@ -115,16 +111,14 @@ define i32 @test_optsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
; OVERIDE-NEXT: [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
; OVERIDE-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
; OVERIDE-NEXT: [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; OVERIDE-NEXT: br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; OVERIDE-NEXT: br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; OVERIDE: 5:
+; OVERIDE-NEXT: br label [[COND_END_THREAD]]
; OVERIDE: cond.end.thread:
-; OVERIDE-NEXT: [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; OVERIDE-NEXT: [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; OVERIDE-NEXT: br label [[TMP6]]
-; OVERIDE: 6:
-; OVERIDE-NEXT: [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; OVERIDE-NEXT: [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; OVERIDE-NEXT: [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; OVERIDE-NEXT: [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; OVERIDE-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; OVERIDE-NEXT: [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; OVERIDE-NEXT: [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; OVERIDE-NEXT: [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
; OVERIDE-NEXT: ret i32 0
;
entry:
diff --git a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
index b8b5aaa73cf501c..2f5fb4f33013d2e 100644
--- a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
+++ b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
@@ -114,3 +114,35 @@ bb0:
call void @foo()
ret void
}
+
+define i8 @common_pred(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: @common_pred(
+; CHECK-NEXT: Pred:
+; CHECK-NEXT: call void @dummy()
+; CHECK-NEXT: br i1 [[C1:%.*]], label [[COMMONPRED:%.*]], label [[SUCC:%.*]]
+; CHECK: CommonPred:
+; CHECK-NEXT: call void @dummy()
+; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C2:%.*]], i8 4, i8 1
+; CHECK-NEXT: br label [[SUCC]]
+; CHECK: Succ:
+; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 0, [[PRED:%.*]] ], [ [[SPEC_SELECT]], [[COMMONPRED]] ]
+; CHECK-NEXT: ret i8 [[PHI2]]
+;
+Pred:
+call void @dummy()
+ br i1 %c1, label %CommonPred, label %BB
+
+CommonPred:
+call void @dummy()
+ br i1 %c2, label %Succ, label %BB
+
+BB:
+ %phi1 = phi i8 [ 0, %Pred ], [1, %CommonPred]
+ br label %Succ
+
+Succ:
+ %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+ ret i8 %phi2
+}
+
+declare void @dummy()
diff --git a/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
new file mode 100644
index 000000000000000..0ffa53a5c9e1049
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
@@ -0,0 +1,327 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
+
+; Test a bunch of cases where the combination of phis in switch should be merged into one phi
+
+declare void @use(i8)
+
+define i8 @phis_of_switch_minimal(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_minimal
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT: start:
+; CHECK-NEXT: switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT: i8 0, label [[CASE01:%.*]]
+; CHECK-NEXT: i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT: i8 2, label [[END:%.*]]
+; CHECK-NEXT: ]
+; CHECK: unreachable:
+; CHECK-NEXT: unreachable
+; CHECK: case1:
+; CHECK-NEXT: br label [[END]]
+; CHECK: case01:
+; CHECK-NEXT: br label [[END]]
+; CHECK: end:
+; CHECK-NEXT: [[PHI2:%.*]] = phi i8 [ 3, [[START:%.*]] ], [ 2, [[CASE1]] ], [ 1, [[CASE01]] ]
+; CHECK-NEXT: ret i8 [[PHI2]]
+;
+start:
+ switch i8 %arg, label %unreachable [
+ i8 0, label %case01
+ i8 1, label %case1
+ i8 2, label %end
+ ]
+unreachable:
+ unreachable
+case1:
+ br label %case01
+
+case01:
+ %phi1 = phi i8 [ 2, %case1 ], [1, %start]
+ br label %end
+
+end:
+ %phi2 = phi i8 [ %phi1, %case01 ], [ 3, %start ]
+ ret i8 %phi2
+}
+
+define i8 @phis_of_switch(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHE...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/68473
More information about the llvm-commits
mailing list