[llvm] [SimplifyCFG] Handle switch-to-select remapping correctly (PR #213302)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 16 01:42:33 PDT 2026
================
@@ -4999,8 +4999,70 @@ bool SimplifyCFGOpt::simplifyTerminatorOnSelect(Instruction *OldTerm,
// (switch (select cond, X, Y)) on constant X, Y
// with a branch - conditional if X and Y lead to distinct BBs,
// unconditional otherwise.
+//
+// Also folds switch(select(icmp eq X, C, K, X)) into switch(X), retargeting
+// (or adding) the case for C to wherever K currently dispatches to:
+// %cmp = icmp eq T %x, C
+// %key = select i1 %cmp, T K, T %x
+// switch T %key, label %default [ T K, label %case_k ... ]
+// becomes
+// switch T %x, label %default [ T C, label %case_k
+// T K, label %case_k ... ]
bool SimplifyCFGOpt::simplifySwitchOnSelect(SwitchInst *SI,
SelectInst *Select) {
+ CmpPredicate Pred;
+ Value *X;
+ ConstantInt *C;
+ if (Select->hasOneUse() &&
+ match(Select->getCondition(),
+ m_OneUse(m_c_ICmp(Pred, m_Value(X), m_ConstantInt(C)))) &&
+ ICmpInst::isEquality(Pred)) {
+ // Normalize to select(icmp eq X, C, K, X).
+ Value *TrueVal = Select->getTrueValue();
+ Value *FalseVal = Select->getFalseValue();
+ if (Pred == ICmpInst::ICMP_NE)
+ std::swap(TrueVal, FalseVal);
+ if (auto *K = (FalseVal == X) ? dyn_cast<ConstantInt>(TrueVal) : nullptr) {
+ BasicBlock *DestFork = SI->findCaseValue(K)->getCaseSuccessor();
+ auto CaseC = SI->findCaseValue(C);
+ bool IsDefault = CaseC == SI->case_default();
+ // Save before setSuccessor()/addCase() change it.
+ BasicBlock *OldDest = CaseC->getCaseSuccessor();
+ BasicBlock *BB = SI->getParent();
+
+ if (OldDest != DestFork) {
+ // Case list is changing so we should drop stale profile weights.
+ SI->setMetadata(LLVMContext::MD_prof, nullptr);
+ if (IsDefault)
+ SI->addCase(C, DestFork);
+ else
+ CaseC->setSuccessor(DestFork);
+ // Not a new edge (BB->DestFork exists via K), just adding the PHI
+ // entry.
+ addPredecessorToBlock(DestFork, BB, BB);
+
+ if (!IsDefault) {
+ // Edge to OldDest is gone only if nothing else still uses it.
+ bool OldDestStillTargeted =
+ SI->getDefaultDest() == OldDest ||
+ any_of(SI->cases(), [&](const SwitchInst::CaseHandle &Case) {
+ return Case.getCaseIndex() != CaseC->getCaseIndex() &&
+ Case.getCaseSuccessor() == OldDest;
+ });
+ for (PHINode &PN : make_early_inc_range(OldDest->phis()))
----------------
dtcxzyw wrote:
Use `OldDest->removePredecessor` instead.
https://github.com/llvm/llvm-project/pull/213302
More information about the llvm-commits
mailing list