[llvm] [SimplifyCFG]: Switch on umin replaces default (PR #164097)

via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 22 06:54:58 PDT 2025


================
@@ -7540,6 +7540,82 @@ static bool reduceSwitchRange(SwitchInst *SI, IRBuilder<> &Builder,
   return true;
 }
 
+/// Tries to transform the switch when the condition is umin with a constant.
+/// In that case, the default branch can be replaced by the constant's branch.
+/// This method also removes dead cases when the simplification cannot replace
+/// the default branch.
+///
+/// For example:
+/// switch(umin(a, 3)) {
+/// case 0:
+/// case 1:
+/// case 2:
+/// case 3:
+/// case 4:
+///   // ...
+/// default:
+///   unreachable
+/// }
+///
+/// Transforms into:
+///
+/// switch(a) {
+/// case 0:
+/// case 1:
+/// case 2:
+/// default:
+///   // This is case 3
+/// }
+static bool simplifySwitchWhenUMin(SwitchInst *SI, DomTreeUpdater *DTU) {
+  Value *A;
+  ConstantInt *Constant;
+
+  if (!match(SI->getCondition(), m_UMin(m_Value(A), m_ConstantInt(Constant))))
+    return false;
+
+  SmallVector<DominatorTree::UpdateType> Updates;
+  SwitchInstProfUpdateWrapper SIW(*SI);
+  BasicBlock *BB = SIW->getParent();
+
+  // Dead cases are removed even when the simplification fails.
+  // A case is dead when its value is higher than the Constant.
+  SmallVector<ConstantInt *, 4> DeadCases;
+  for (auto Case : SI->cases())
+    if (Case.getCaseValue()->getValue().ugt(Constant->getValue()))
+      DeadCases.push_back(Case.getCaseValue());
+
+  for (ConstantInt *DeadCaseVal : DeadCases) {
+    SwitchInst::CaseIt DeadCase = SIW->findCaseValue(DeadCaseVal);
+    BasicBlock *DeadCaseBB = DeadCase->getCaseSuccessor();
+    DeadCaseBB->removePredecessor(SIW->getParent());
+    SIW.removeCase(DeadCase);
+    Updates.push_back({DominatorTree::Delete, BB, DeadCaseBB});
+  }
+
+  auto Case = SI->findCaseValue(Constant);
+  // If the case value is not found, `findCaseValue` returns the default case.
+  // In this scenario, since there is no explicit `case 3:`, the simplification
+  // fails. The simplification also fails when the switch’s default destination
+  // is reachable.
+  if (!SI->defaultDestUnreachable() || Case == SI->case_default()) {
+    if (DTU)
+      DTU->applyUpdates(Updates);
+    return false;
+  }
+
+  BasicBlock *Unreachable = SI->getDefaultDest();
+  SIW.replaceDefaultDest(Case);
+  SIW.removeCase(Case);
+  SIW->setCondition(A);
+
+  Updates.push_back({DominatorTree::Delete, BB, Unreachable});
+
+  if (DTU)
+    DTU->applyUpdates(Updates);
+
+  return true;
----------------
kper wrote:

ah yes, sloppy oversight when I moved the dead cases to the top
thank you for catching this

I did not introduce a new variable but added a check when the `Updates` is empty

https://github.com/llvm/llvm-project/pull/164097


More information about the llvm-commits mailing list