[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