[llvm] Reland "[SimplifyCFG] Simplify switch default branch when branch proves operand value" (PR #211427)

Sayan Sivakumaran via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 23 08:59:16 PDT 2026


https://github.com/sivakusayan updated https://github.com/llvm/llvm-project/pull/211427

>From 9d5257b6351156bf93f3d3127760d786b26c599c Mon Sep 17 00:00:00 2001
From: Sayan Sivakumaran <sivakusayan at gmail.com>
Date: Wed, 22 Jul 2026 18:35:49 -0500
Subject: [PATCH 1/2] [SimplifyCFG] Simplify switch default branch when branch
 proves operand value

---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp     |  41 +++
 .../SimplifyCFG/switch-simplify-default.ll    | 297 ++++++++++++++++++
 2 files changed, 338 insertions(+)
 create mode 100644 llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index ca6ae94a9a8d9..5a082bf6575b5 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -7857,6 +7857,44 @@ static bool simplifySwitchWhenUMin(SwitchInst *SI, DomTreeUpdater *DTU) {
   return true;
 }
 
+static bool simplifySwitchDefaultBranch(SwitchInst *SI, DomTreeUpdater *DTU,
+                                        const DataLayout &DL,
+                                        AssumptionCache *AC) {
+  assert(SI);
+  if (SI->defaultDestUnreachable())
+    return false;
+
+  // If it can be proved that the switch condition takes some concrete value
+  // in the default block, we can make some nice simplifications to the
+  // switch.
+  BasicBlock *Default = SI->getDefaultDest();
+  const Instruction *CxtI = &*Default->getFirstNonPHIIt();
+  const KnownBits Known = computeKnownBits(
+      SI->getCondition(),
+      SimplifyQuery(DL, /*DT=*/nullptr, AC, CxtI).allowEphemerals(true));
+  if (!Known.isConstant())
+    return false;
+
+  // At this point, we know that only one value can be mapped to the
+  // default block. So, if a case doesn't exist for it already, we
+  // can create one pointing to the default block.
+  ConstantInt *CaseVal =
+      ConstantInt::get(SI->getContext(), Known.getConstant());
+  const llvm::SwitchInst::CaseIt CaseIt = SI->findCaseValue(CaseVal);
+  if (CaseIt == SI->case_default()) {
+    SwitchInstProfUpdateWrapper SIW(*SI);
+    SIW.addCase(CaseVal, Default, SIW.getSuccessorWeight(0));
+    SIW.setSuccessorWeight(0, 0);
+  }
+  createUnreachableSwitchDefault(SI, DTU, /*RemoveOrigDefaultBlock*/ false);
+
+  assert(SI->getNumCases() > 0 && "Switch should have at least one case");
+  assert(SI->findCaseValue(CaseVal) != SI->case_default() &&
+         "Proven value should have a dedicated case");
+  assert(SI->defaultDestUnreachable());
+  return true;
+}
+
 /// Tries to transform switch of powers of two to reduce switch range.
 /// For example, switch like:
 /// switch (C) { case 1: case 2: case 64: case 128: }
@@ -8397,6 +8435,9 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
   if (simplifySwitchWhenUMin(SI, DTU))
     return requestResimplify();
 
+  if (simplifySwitchDefaultBranch(SI, DTU, DL, Options.AC))
+    return requestResimplify();
+
   return false;
 }
 
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll b/llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll
new file mode 100644
index 0000000000000..e81911c9064e5
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll
@@ -0,0 +1,297 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
+
+define i32 @default_branch_proves_operand_value(i8 %x) {
+; CHECK-LABEL: @default_branch_proves_operand_value(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[DEFAULT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       default:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  ]
+default:
+  %cmp = icmp eq i8 %x, 1
+  call void @llvm.assume(i1 %cmp)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
+define i32 @default_branch_with_weight_proves_operand_value(i8 %x) {
+; CHECK-LABEL: @default_branch_with_weight_proves_operand_value(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[DEFAULT:%.*]]
+; CHECK-NEXT:    ], !prof [[PROF0:![0-9]+]]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       default:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  ], !prof !0
+
+default:
+  %cmp = icmp eq i8 %x, 1
+  call void @llvm.assume(i1 %cmp)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
+define i32 @default_branch_proves_operand_value_different_blocks(i8 %x) {
+; CHECK-LABEL: @default_branch_proves_operand_value_different_blocks(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 1
+; CHECK-NEXT:    switch i8 [[X]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[DEFAULT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       default:
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+entry:
+  %cmp = icmp eq i8 %x, 1
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  ]
+default:
+  call void @llvm.assume(i1 %cmp)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
+declare void @foo(i8 %bar) nounwind
+define i32 @default_branch_proves_operand_value_assume_operand_not_ephemeral(i8 %x) {
+; CHECK-LABEL: @default_branch_proves_operand_value_assume_operand_not_ephemeral(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[DEFAULT:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       default:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    call void @foo(i1 [[CMP]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  ]
+default:
+  %cmp = icmp eq i8 %x, 1
+  call void @llvm.assume(i1 %cmp)
+  call void @foo(i1 %cmp)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
+define i32 @default_branch_proves_operand_value_but_has_existing_case(i8 %x) {
+; CHECK-LABEL: @default_branch_proves_operand_value_but_has_existing_case(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[CASE_ONE:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_one:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[CASE_ONE]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  i8 1, label %case_one
+  ]
+
+default:
+  %cmp = icmp eq i8 %x, 1
+  call void @llvm.assume(i1 %cmp)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+case_one:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ], [1, %case_one ]
+  ret i32 %retval
+}
+
+define i32 @default_branch_assume_doesnt_prove_all_bits(i8 %x) {
+; CHECK-LABEL: @default_branch_assume_doesnt_prove_all_bits(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       default:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i8 [[X]], 10
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  ]
+
+default:
+  %cmp = icmp ule i8 %x, 10
+  call void @llvm.assume(i1 %cmp)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
+declare void @foo_may_unwind()
+define i32 @default_branch_may_throw_before_assume(i8 %x) {
+; CHECK-LABEL: @default_branch_may_throw_before_assume(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       default:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X]], 1
+; CHECK-NEXT:    call void @foo_may_unwind()
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[ENTRY_UNREACHABLEDEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  ]
+default:
+  %cmp = icmp eq i8 %x, 1
+  call void @foo_may_unwind()
+  call void @llvm.assume(i1 %cmp)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 0, i32 4, i32 2, i32 8}
+!0 = !{!"branch_weights", i32 8, i32 4, i32 2}

>From f4a8d709067e879cf16a074aba20068bee9d612c Mon Sep 17 00:00:00 2001
From: Sayan Sivakumaran <sivakusayan at gmail.com>
Date: Wed, 22 Jul 2026 18:37:29 -0500
Subject: [PATCH 2/2] Properly handle PHINodes in default branch we are
 simplifying

---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp     |   2 +
 .../SimplifyCFG/switch-simplify-default.ll    | 159 ++++++++++++++++++
 2 files changed, 161 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 5a082bf6575b5..1cde16d9558e6 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -7885,6 +7885,8 @@ static bool simplifySwitchDefaultBranch(SwitchInst *SI, DomTreeUpdater *DTU,
     SwitchInstProfUpdateWrapper SIW(*SI);
     SIW.addCase(CaseVal, Default, SIW.getSuccessorWeight(0));
     SIW.setSuccessorWeight(0, 0);
+  } else {
+    Default->removePredecessor(SI->getParent());
   }
   createUnreachableSwitchDefault(SI, DTU, /*RemoveOrigDefaultBlock*/ false);
 
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll b/llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll
index e81911c9064e5..6ea6115147a8f 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch-simplify-default.ll
@@ -293,5 +293,164 @@ return:
   ret i32 %retval
 }
 
+; Make sure to properly update PHINode block entries if the default branch
+; happens to have them.
+declare i1 @some_use(i8)
+define i32 @default_branch_has_phi_and_will_be_moved(i8 %x, i1 %y) {
+; CHECK-LABEL: @default_branch_has_phi_and_will_be_moved(
+; CHECK-NEXT:  pre-entry:
+; CHECK-NEXT:    br i1 [[Y:%.*]], label [[ENTRY:%.*]], label [[DEFAULT:%.*]]
+; CHECK:       entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[DEFAULT]]
+; CHECK-NEXT:    ]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       default:
+; CHECK-NEXT:    [[Z:%.*]] = phi i8 [ 2, [[PRE_ENTRY:%.*]] ], [ 3, [[ENTRY]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    call void @some_use(i8 [[Z]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+pre-entry:
+  br i1 %y, label %entry, label %default
+
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  ]
+default:
+  %z = phi i8 [ 2, %pre-entry], [ 3, %entry]
+  %cmp = icmp eq i8 %x, 1
+  call void @llvm.assume(i1 %cmp)
+  call void @some_use(i8 %z)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
+define i32 @default_branch_has_phi_and_will_be_removed(i8 %x, i1 %y) {
+; CHECK-LABEL: @default_branch_has_phi_and_will_be_removed(
+; CHECK-NEXT:  pre-entry:
+; CHECK-NEXT:    br i1 [[Y:%.*]], label [[ENTRY:%.*]], label [[DEFAULT:%.*]]
+; CHECK:       entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[CASE_ONE:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       default:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    call void @some_use(i8 2)
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_one:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 1, [[CASE_ONE]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+pre-entry:
+  br i1 %y, label %entry, label %default
+
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  i8 1, label %case_one
+  ]
+default:
+  %z = phi i8 [ 2, %pre-entry], [ 3, %entry]
+  %cmp = icmp eq i8 %x, 1
+  call void @llvm.assume(i1 %cmp)
+  call void @some_use(i8 %z)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+case_one:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ], [ 1, %case_one ]
+  ret i32 %retval
+}
+
+define i32 @default_branch_has_phi_and_will_be_removed_duplicate_phi_entries(i8 %x, i1 %y) {
+; CHECK-LABEL: @default_branch_has_phi_and_will_be_removed_duplicate_phi_entries(
+; CHECK-NEXT:  pre-entry:
+; CHECK-NEXT:    br i1 [[Y:%.*]], label [[ENTRY:%.*]], label [[DEFAULT:%.*]]
+; CHECK:       entry:
+; CHECK-NEXT:    switch i8 [[X:%.*]], label [[ENTRY_UNREACHABLEDEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[RETURN:%.*]]
+; CHECK-NEXT:      i8 0, label [[CASE_ZERO:%.*]]
+; CHECK-NEXT:      i8 1, label [[DEFAULT]]
+; CHECK-NEXT:    ]
+; CHECK:       entry.unreachabledefault:
+; CHECK-NEXT:    unreachable
+; CHECK:       default:
+; CHECK-NEXT:    [[Z:%.*]] = phi i8 [ 2, [[PRE_ENTRY:%.*]] ], [ 3, [[ENTRY]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    call void @some_use(i8 [[Z]])
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       case_zero:
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL:%.*]] = phi i32 [ 1, [[DEFAULT]] ], [ 0, [[CASE_ZERO]] ], [ -1, [[ENTRY]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL]]
+;
+pre-entry:
+  br i1 %y, label %entry, label %default
+
+entry:
+  switch i8 %x, label %default [
+  i8 -1, label %case_neg_one
+  i8 0, label %case_zero
+  i8 1, label %default
+  ]
+default:
+  %z = phi i8 [ 2, %pre-entry], [ 3, %entry], [ 3, %entry ]
+  %cmp = icmp eq i8 %x, 1
+  call void @llvm.assume(i1 %cmp)
+  call void @some_use(i8 %z)
+  br label %return
+
+case_neg_one:
+  br label %return
+
+case_zero:
+  br label %return
+
+return:
+  %retval = phi i32 [ 1, %default ], [ -1, %case_neg_one ], [ 0, %case_zero ]
+  ret i32 %retval
+}
+
 ; CHECK: [[PROF0]] = !{!"branch_weights", i32 0, i32 4, i32 2, i32 8}
 !0 = !{!"branch_weights", i32 8, i32 4, i32 2}



More information about the llvm-commits mailing list