[llvm] [SimplifyCFG] Restrict initializer checks to lookup tables (PR #224235)

Alex MacLean via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 17 02:00:29 PDT 2026


https://github.com/AlexMaclean created https://github.com/llvm/llvm-project/pull/224235

SimplifyCFG currently applies lookup table constant restrictions even when a switch can be replaced with selects or other SSA values. Move these checks to lookup table construction so they only apply when a global initializer is needed.

>From cb58d7e6b0ecfde6319628f399a953e3a04b698c Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Thu, 17 Sep 2026 01:56:31 -0700
Subject: [PATCH] [SimplifyCFG] Restrict initializer checks to lookup tables

---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp     |  52 +++---
 .../ARM/switch-ssa-lookup-restrictions.ll     |  97 +++++++++++
 .../X86/switch-result-constants.ll            | 160 ++++++++++++++++++
 3 files changed, 289 insertions(+), 20 deletions(-)
 create mode 100644 llvm/test/Transforms/SimplifyCFG/ARM/switch-ssa-lookup-restrictions.ll
 create mode 100644 llvm/test/Transforms/SimplifyCFG/X86/switch-result-constants.ll

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 668c0e819015a..907aea5a085bc 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6641,7 +6641,7 @@ static bool
 getCaseResults(SwitchInst *SI, ConstantInt *CaseVal, BasicBlock *CaseDest,
                BasicBlock **CommonDest,
                SmallVectorImpl<std::pair<PHINode *, Constant *>> &Res,
-               const DataLayout &DL, const TargetTransformInfo &TTI) {
+               const DataLayout &DL) {
   // The block from which we enter the common destination.
   BasicBlock *Pred = SI->getParent();
 
@@ -6697,10 +6697,6 @@ getCaseResults(SwitchInst *SI, ConstantInt *CaseVal, BasicBlock *CaseDest,
     if (!ConstVal)
       return false;
 
-    // Be conservative about which kinds of constants we support.
-    if (!validLookupTableConstant(ConstVal, TTI))
-      return false;
-
     Res.push_back(std::make_pair(&PHI, ConstVal));
   }
 
@@ -6732,7 +6728,6 @@ static bool initializeUniqueCases(SwitchInst *SI, PHINode *&PHI,
                                   SwitchCaseResultVectorTy &UniqueResults,
                                   Constant *&DefaultResult,
                                   const DataLayout &DL,
-                                  const TargetTransformInfo &TTI,
                                   uintptr_t MaxUniqueResults) {
   for (const auto &I : SI->cases()) {
     ConstantInt *CaseVal = I.getCaseValue();
@@ -6740,7 +6735,7 @@ static bool initializeUniqueCases(SwitchInst *SI, PHINode *&PHI,
     // Resulting value at phi nodes for this case value.
     SwitchCaseResultsTy Results;
     if (!getCaseResults(SI, CaseVal, I.getCaseSuccessor(), &CommonDest, Results,
-                        DL, TTI))
+                        DL))
       return false;
 
     // Only one value per case is permitted.
@@ -6768,7 +6763,7 @@ static bool initializeUniqueCases(SwitchInst *SI, PHINode *&PHI,
   // Find the default result value.
   SmallVector<std::pair<PHINode *, Constant *>, 1> DefaultResults;
   getCaseResults(SI, nullptr, SI->getDefaultDest(), &CommonDest, DefaultResults,
-                 DL, TTI);
+                 DL);
   // If the default value is not found abort unless the default destination
   // is unreachable.
   DefaultResult =
@@ -6975,8 +6970,7 @@ static void removeSwitchAfterSelectFold(SwitchInst *SI, PHINode *PHI,
 /// successor block with only two different constant values, try to replace the
 /// switch with a select. Returns true if the fold was made.
 static bool trySwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder,
-                              DomTreeUpdater *DTU, const DataLayout &DL,
-                              const TargetTransformInfo &TTI) {
+                              DomTreeUpdater *DTU, const DataLayout &DL) {
   Value *const Cond = SI->getCondition();
   PHINode *PHI = nullptr;
   BasicBlock *CommonDest = nullptr;
@@ -6984,7 +6978,7 @@ static bool trySwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder,
   SwitchCaseResultVectorTy UniqueResults;
   // Collect all the cases that will deliver the same value from the switch.
   if (!initializeUniqueCases(SI, PHI, CommonDest, UniqueResults, DefaultResult,
-                             DL, TTI, /*MaxUniqueResults*/ 2))
+                             DL, /*MaxUniqueResults*/ 2))
     return false;
 
   assert(PHI != nullptr && "PHI for value select not found");
@@ -7015,6 +7009,7 @@ class SwitchReplacement {
   /// Create a helper for optimizations to use as a switch replacement.
   /// Find a better representation for the content of Values,
   /// using DefaultValue to fill any holes in the table.
+  /// If no representation is possible, isValid() returns false.
   SwitchReplacement(
       Module &M, uint64_t TableSize, ConstantInt *Offset,
       const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
@@ -7040,9 +7035,15 @@ class SwitchReplacement {
   /// Return true if the replacement is a bit map.
   bool isBitMap();
 
+  /// Return true if a suitable switch replacement was found.
+  bool isValid() const { return Kind != InvalidKind; }
+
 private:
   // Depending on the switch, there are different alternatives.
   enum {
+    // No suitable replacement was found.
+    InvalidKind,
+
     // For switches where each case contains the same value, we just have to
     // store that single value and return it for each lookup.
     SingleValueKind,
@@ -7160,8 +7161,7 @@ SwitchReplacement::SwitchReplacement(
       }
 
       if (!ConstVal) {
-        // This is an undef. We could deal with it, but undefs in lookup tables
-        // are very seldom. It's probably not worth the additional complexity.
+        // We only handle literal integers when checking for a linear mapping.
         LinearMappingPossible = false;
         break;
       }
@@ -7192,8 +7192,10 @@ SwitchReplacement::SwitchReplacement(
     }
   }
 
-  // If the type is integer and the table fits in a register, build a bitmap.
-  if (wouldFitInRegister(DL, TableSize, ValueType)) {
+  // If the values are integer constants and the table fits in a register,
+  // build a bitmap.
+  if (wouldFitInRegister(DL, TableSize, ValueType) &&
+      all_of(TableContents, IsaPred<ConstantInt, UndefValue>)) {
     IntegerType *IT = cast<IntegerType>(ValueType);
     APInt TableInt(TableSize * IT->getBitWidth(), 0);
     for (uint64_t I = TableSize; I > 0; --I) {
@@ -7210,6 +7212,13 @@ SwitchReplacement::SwitchReplacement(
     return;
   }
 
+  // The remaining representation needs a global initializer.
+  if (!all_of(TableContents,
+              [&](Constant *C) { return validLookupTableConstant(C, TTI); })) {
+    Kind = InvalidKind;
+    return;
+  }
+
   if (auto *IT = dyn_cast<IntegerType>(ValueType)) {
     ConstantRange Range(IT->getBitWidth(), false);
     for (Constant *Value : TableContents)
@@ -7236,6 +7245,8 @@ SwitchReplacement::SwitchReplacement(
 Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
                                         const DataLayout &DL, Function *Func) {
   switch (Kind) {
+  case InvalidKind:
+    llvm_unreachable("Cannot use an invalid switch replacement");
   case SingleValueKind:
     return SingleValue;
   case LinearMapKind: {
@@ -7601,7 +7612,7 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
     using ResultsTy = SmallVector<std::pair<PHINode *, Constant *>, 4>;
     ResultsTy Results;
     if (!getCaseResults(SI, CaseVal, CI->getCaseSuccessor(), &CommonDest,
-                        Results, DL, TTI))
+                        Results, DL))
       return false;
 
     // Append the result and result types from this case to the list for each
@@ -7620,9 +7631,8 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
   // If the table has holes, we need a constant result for the default case
   // or a bitmask that fits in a register.
   SmallVector<std::pair<PHINode *, Constant *>, 4> DefaultResultsList;
-  bool HasDefaultResults =
-      getCaseResults(SI, nullptr, SI->getDefaultDest(), &CommonDest,
-                     DefaultResultsList, DL, TTI);
+  bool HasDefaultResults = getCaseResults(SI, nullptr, SI->getDefaultDest(),
+                                          &CommonDest, DefaultResultsList, DL);
   for (const auto &I : DefaultResultsList) {
     PHINode *PHI = I.first;
     Constant *Result = I.second;
@@ -7716,6 +7726,8 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
     StringRef FuncName = Fn->getName();
     SwitchReplacement Replacement(*Fn->getParent(), TableSize, TableIndexOffset,
                                   ResultList, DefaultVal, DL, TTI, FuncName);
+    if (!Replacement.isValid())
+      return false;
     PhiToReplacementMap.insert({PHI, Replacement});
   }
 
@@ -8611,7 +8623,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
   if (simplifySwitchOfCmpIntrinsic(SI, Builder, DTU))
     return requestResimplify();
 
-  if (trySwitchToSelect(SI, Builder, DTU, DL, TTI))
+  if (trySwitchToSelect(SI, Builder, DTU, DL))
     return requestResimplify();
 
   if (Options.ForwardSwitchCondToPhi && forwardSwitchConditionToPHI(SI))
diff --git a/llvm/test/Transforms/SimplifyCFG/ARM/switch-ssa-lookup-restrictions.ll b/llvm/test/Transforms/SimplifyCFG/ARM/switch-ssa-lookup-restrictions.ll
new file mode 100644
index 0000000000000..fd2e0d0e325be
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/ARM/switch-ssa-lookup-restrictions.ll
@@ -0,0 +1,97 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt -S -passes='simplifycfg<switch-to-lookup>' -mtriple=arm -relocation-model=static < %s | FileCheck %s
+; RUN: opt -S -passes='simplifycfg<switch-to-lookup>' -mtriple=arm -relocation-model=ropi < %s | FileCheck %s
+; RUN: opt -S -passes='simplifycfg<switch-to-lookup>' -mtriple=arm -relocation-model=rwpi < %s | FileCheck %s
+; RUN: opt -S -passes='simplifycfg<switch-to-lookup>' -mtriple=arm -relocation-model=ropi-rwpi < %s | FileCheck %s
+
+ at a = external global [4 x i32]
+ at b = external global i32
+ at c = external global i32
+
+; ROPI/RWPI disallow these addresses in lookup table initializers, but they can
+; still be used as select operands, including the default result.
+;.
+; CHECK: @a = external global [4 x i32]
+; CHECK: @b = external global i32
+; CHECK: @c = external global i32
+; CHECK: @switch.table.mixed_replacements = private unnamed_addr constant [4 x i16] [i16 1234, i16 5678, i16 15532, i16 8910], align 4
+;.
+define ptr @select_addresses(i32 %x) {
+; CHECK-LABEL: define ptr @select_addresses(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[X]], 1
+; CHECK-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP]], ptr @b, ptr @c
+; CHECK-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[X]], 0
+; CHECK-NEXT:    [[SWITCH_SELECT2:%.*]] = select i1 [[SWITCH_SELECTCMP1]], ptr getelementptr inbounds ([4 x i32], ptr @a, i32 0, i32 1), ptr [[SWITCH_SELECT]]
+; CHECK-NEXT:    ret ptr [[SWITCH_SELECT2]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  ]
+case0:
+  br label %return
+case1:
+  br label %return
+default:
+  br label %return
+return:
+  %r = phi ptr [ getelementptr inbounds ([4 x i32], ptr @a, i32 0, i32 1), %case0 ], [ @b, %case1 ], [ @c, %default ]
+  ret ptr %r
+}
+
+declare void @use(ptr, i32, i8, i32)
+
+; Each PHI gets its own replacement: a single pointer value, a linear map, a
+; bitmap, and an integer lookup table. Only the last needs a global initializer.
+define void @mixed_replacements(i32 %x) {
+; CHECK-LABEL: define void @mixed_replacements(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[X]], 4
+; CHECK-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK:       [[SWITCH_LOOKUP]]:
+; CHECK-NEXT:    [[SWITCH_IDX_MULT:%.*]] = mul nsw i32 [[X]], 3
+; CHECK-NEXT:    [[SWITCH_OFFSET:%.*]] = add nsw i32 [[SWITCH_IDX_MULT]], 3
+; CHECK-NEXT:    [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i32 [[X]], 8
+; CHECK-NEXT:    [[SWITCH_DOWNSHIFT:%.*]] = lshr i32 33620483, [[SWITCH_SHIFTAMT]]
+; CHECK-NEXT:    [[SWITCH_MASKED:%.*]] = trunc i32 [[SWITCH_DOWNSHIFT]] to i8
+; CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i16], ptr @switch.table.mixed_replacements, i32 0, i32 [[X]]
+; CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i16, ptr [[SWITCH_GEP]], align 2
+; CHECK-NEXT:    [[SWITCH_EXT:%.*]] = zext i16 [[SWITCH_LOAD]] to i32
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[RETURN]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ @a, %[[SWITCH_LOOKUP]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT:    [[LINEAR:%.*]] = phi i32 [ [[SWITCH_OFFSET]], %[[SWITCH_LOOKUP]] ], [ -1, %[[ENTRY]] ]
+; CHECK-NEXT:    [[BITMAP:%.*]] = phi i8 [ [[SWITCH_MASKED]], %[[SWITCH_LOOKUP]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT:    [[TABLE:%.*]] = phi i32 [ [[SWITCH_EXT]], %[[SWITCH_LOOKUP]] ], [ -1, %[[ENTRY]] ]
+; CHECK-NEXT:    call void @use(ptr [[P]], i32 [[LINEAR]], i8 [[BITMAP]], i32 [[TABLE]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  ]
+case0:
+  br label %return
+case1:
+  br label %return
+case2:
+  br label %return
+case3:
+  br label %return
+default:
+  br label %return
+return:
+  %p = phi ptr [ @a, %case0 ], [ @a, %case1 ], [ @a, %case2 ], [ @a, %case3 ], [ null, %default ]
+  %linear = phi i32 [ 3, %case0 ], [ 6, %case1 ], [ 9, %case2 ], [ 12, %case3 ], [ -1, %default ]
+  %bitmap = phi i8 [ 3, %case0 ], [ 2, %case1 ], [ 1, %case2 ], [ 2, %case3 ], [ 0, %default ]
+  %table = phi i32 [ 1234, %case0 ], [ 5678, %case1 ], [ 15532, %case2 ], [ 8910, %case3 ], [ -1, %default ]
+  call void @use(ptr %p, i32 %linear, i8 %bitmap, i32 %table)
+  ret void
+}
diff --git a/llvm/test/Transforms/SimplifyCFG/X86/switch-result-constants.ll b/llvm/test/Transforms/SimplifyCFG/X86/switch-result-constants.ll
new file mode 100644
index 0000000000000..9375df21dbbc1
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/X86/switch-result-constants.ll
@@ -0,0 +1,160 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt -S -passes='simplifycfg<switch-to-lookup>' -verify-each < %s | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+ at a = external global i32
+ at b = external global i32
+ at c = external global i32
+ at d = external global i32
+
+; These constants are valid select operands, regardless of whether they can
+; be used in a lookup table initializer.
+;.
+; CHECK: @a = external global i32
+; CHECK: @b = external global i32
+; CHECK: @c = external global i32
+; CHECK: @d = external global i32
+;.
+define <vscale x 4 x i32> @select_scalable(i32 %x) {
+; CHECK-LABEL: define <vscale x 4 x i32> @select_scalable(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[X]], 1
+; CHECK-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP]], <vscale x 4 x i32> splat (i32 7), <vscale x 4 x i32> zeroinitializer
+; CHECK-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[X]], 0
+; CHECK-NEXT:    [[SWITCH_SELECT2:%.*]] = select i1 [[SWITCH_SELECTCMP1]], <vscale x 4 x i32> splat (i32 3), <vscale x 4 x i32> [[SWITCH_SELECT]]
+; CHECK-NEXT:    ret <vscale x 4 x i32> [[SWITCH_SELECT2]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  ]
+case0:
+  br label %return
+case1:
+  br label %return
+default:
+  br label %return
+return:
+  %r = phi <vscale x 4 x i32> [ splat (i32 3), %case0 ], [ splat (i32 7), %case1 ], [ zeroinitializer, %default ]
+  ret <vscale x 4 x i32> %r
+}
+
+define i64 @select_constant_expr(i32 %x) {
+; CHECK-LABEL: define i64 @select_constant_expr(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[X]], 1
+; CHECK-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP]], i64 7, i64 0
+; CHECK-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[X]], 0
+; CHECK-NEXT:    [[SWITCH_SELECT2:%.*]] = select i1 [[SWITCH_SELECTCMP1]], i64 ptrtoint (ptr @a to i64), i64 [[SWITCH_SELECT]]
+; CHECK-NEXT:    ret i64 [[SWITCH_SELECT2]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  ]
+case0:
+  br label %return
+case1:
+  br label %return
+default:
+  br label %return
+return:
+  %r = phi i64 [ ptrtoint (ptr @a to i64), %case0 ], [ 7, %case1 ], [ 0, %default ]
+  ret i64 %r
+}
+
+; Integer-typed expressions cannot be packed into a bitmap, even when their
+; types fit. They also fail the lookup table initializer checks.
+define i8 @no_bitmap_constant_expr(i32 %x) {
+; CHECK-LABEL: define i8 @no_bitmap_constant_expr(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    switch i32 [[X]], label %[[DEFAULT:.*]] [
+; CHECK-NEXT:      i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT:      i32 1, label %[[CASE1:.*]]
+; CHECK-NEXT:      i32 2, label %[[CASE2:.*]]
+; CHECK-NEXT:      i32 3, label %[[CASE3:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[CASE1]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[CASE2]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[CASE3]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[DEFAULT]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[RETURN]]:
+; CHECK-NEXT:    [[R:%.*]] = phi i8 [ 0, %[[DEFAULT]] ], [ ptrtoint (ptr @b to i8), %[[CASE1]] ], [ ptrtoint (ptr @c to i8), %[[CASE2]] ], [ ptrtoint (ptr @d to i8), %[[CASE3]] ], [ ptrtoint (ptr @a to i8), %[[ENTRY]] ]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  ]
+case0:
+  br label %return
+case1:
+  br label %return
+case2:
+  br label %return
+case3:
+  br label %return
+default:
+  br label %return
+return:
+  %r = phi i8 [ ptrtoint (ptr @a to i8), %case0 ], [ ptrtoint (ptr @b to i8), %case1 ], [ ptrtoint (ptr @c to i8), %case2 ], [ ptrtoint (ptr @d to i8), %case3 ], [ 0, %default ]
+  ret i8 %r
+}
+
+; The larger type reaches lookup table validation before integer narrowing.
+define i64 @no_table_constant_expr(i32 %x) {
+; CHECK-LABEL: define i64 @no_table_constant_expr(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    switch i32 [[X]], label %[[DEFAULT:.*]] [
+; CHECK-NEXT:      i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT:      i32 1, label %[[CASE1:.*]]
+; CHECK-NEXT:      i32 2, label %[[CASE2:.*]]
+; CHECK-NEXT:      i32 3, label %[[CASE3:.*]]
+; CHECK-NEXT:    ]
+; CHECK:       [[CASE1]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[CASE2]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[CASE3]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[DEFAULT]]:
+; CHECK-NEXT:    br label %[[RETURN]]
+; CHECK:       [[RETURN]]:
+; CHECK-NEXT:    [[R:%.*]] = phi i64 [ 0, %[[DEFAULT]] ], [ ptrtoint (ptr @b to i64), %[[CASE1]] ], [ ptrtoint (ptr @c to i64), %[[CASE2]] ], [ ptrtoint (ptr @d to i64), %[[CASE3]] ], [ ptrtoint (ptr @a to i64), %[[ENTRY]] ]
+; CHECK-NEXT:    ret i64 [[R]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  ]
+case0:
+  br label %return
+case1:
+  br label %return
+case2:
+  br label %return
+case3:
+  br label %return
+default:
+  br label %return
+return:
+  %r = phi i64 [ ptrtoint (ptr @a to i64), %case0 ], [ ptrtoint (ptr @b to i64), %case1 ], [ ptrtoint (ptr @c to i64), %case2 ], [ ptrtoint (ptr @d to i64), %case3 ], [ 0, %default ]
+  ret i64 %r
+}



More information about the llvm-commits mailing list