[llvm] 89d86b6 - SimplifyCFG: Enable switch replacements in more cases (#156477)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 9 07:24:56 PDT 2025


Author: Jessica Del
Date: 2025-09-09T16:24:52+02:00
New Revision: 89d86b626cb29fbd7b476ea6f082256691444ad5

URL: https://github.com/llvm/llvm-project/commit/89d86b626cb29fbd7b476ea6f082256691444ad5
DIFF: https://github.com/llvm/llvm-project/commit/89d86b626cb29fbd7b476ea6f082256691444ad5.diff

LOG: SimplifyCFG: Enable switch replacements in more cases (#156477)

In some cases, we can replace a switch with simpler instructions or a
lookup table.
For instance, if every case results in the same value, we can simply
replace the switch
with that single value.

However, lookup tables are not always supported. 
Targets, function attributes and compiler options can deactivate lookup
table creation.
Currently, even simpler switch replacements like the single value
optimization do not
get applied, because we only enable these transformations if lookup
tables are enabled.

This PR enables the other kinds of replacements, even if lookup tables
are not supported.
First, it checks if the potential replacements are lookup tables.
If they are, then check if lookup tables are supported and whether to
continue.
If they are not, then we can apply the other transformations.

Originally, lookup table creation was delayed until late stages of the
compilation pipeline, because
it can result in difficult-to-analyze code and prevent other
optimizations.
As a side effect of this change, we can also enable the simpler
optimizations much earlier in the
compilation process.

Added: 
    llvm/test/Transforms/SimplifyCFG/switch-transformations-no-lut.ll

Modified: 
    llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 39edc4d871262..970f85378d3d2 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6458,6 +6458,9 @@ class SwitchReplacement {
   /// Return the default value of the switch.
   Constant *getDefaultValue();
 
+  /// Return true if the replacement is a lookup table.
+  bool isLookupTable();
+
 private:
   // Depending on the switch, there are 
diff erent alternatives.
   enum {
@@ -6605,7 +6608,6 @@ SwitchReplacement::SwitchReplacement(
         (void)M.smul_ov(APInt(M.getBitWidth(), TableSize - 1), MayWrap);
       LinearMapValWrapped = NonMonotonic || MayWrap;
       Kind = LinearMapKind;
-      ++NumLinearMaps;
       return;
     }
   }
@@ -6625,7 +6627,6 @@ SwitchReplacement::SwitchReplacement(
     BitMap = ConstantInt::get(M.getContext(), TableInt);
     BitMapElementTy = IT;
     Kind = BitMapKind;
-    ++NumBitMaps;
     return;
   }
 
@@ -6642,6 +6643,7 @@ Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
   case SingleValueKind:
     return SingleValue;
   case LinearMapKind: {
+    ++NumLinearMaps;
     // Derive the result value from the input value.
     Value *Result = Builder.CreateIntCast(Index, LinearMultiplier->getType(),
                                           false, "switch.idx.cast");
@@ -6657,6 +6659,7 @@ Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
     return Result;
   }
   case BitMapKind: {
+    ++NumBitMaps;
     // Type of the bitmap (e.g. i59).
     IntegerType *MapTy = BitMap->getIntegerType();
 
@@ -6679,6 +6682,7 @@ Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
     return Builder.CreateTrunc(DownShifted, BitMapElementTy, "switch.masked");
   }
   case LookupTableKind: {
+    ++NumLookupTables;
     auto *Table =
         new GlobalVariable(*Func->getParent(), Initializer->getType(),
                            /*isConstant=*/true, GlobalVariable::PrivateLinkage,
@@ -6745,6 +6749,8 @@ static bool isTypeLegalForLookupTable(Type *Ty, const TargetTransformInfo &TTI,
 
 Constant *SwitchReplacement::getDefaultValue() { return DefaultValue; }
 
+bool SwitchReplacement::isLookupTable() { return Kind == LookupTableKind; }
+
 static bool isSwitchDense(uint64_t NumCases, uint64_t CaseRange) {
   // 40% is the default density for building a jump table in optsize/minsize
   // mode. See also TargetLoweringBase::isSuitableForJumpTable(), which this
@@ -6915,11 +6921,6 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
 
   BasicBlock *BB = SI->getParent();
   Function *Fn = BB->getParent();
-  // Only build lookup table when we have a target that supports it or the
-  // attribute is not set.
-  if (!TTI.shouldBuildLookupTables() ||
-      (Fn->getFnAttribute("no-jump-tables").getValueAsBool()))
-    return false;
 
   // FIXME: If the switch is too sparse for a lookup table, perhaps we could
   // split off a dense part and build a lookup table for that.
@@ -7078,6 +7079,20 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
     PhiToReplacementMap.insert({PHI, Replacement});
   }
 
+  bool AnyLookupTables = any_of(
+      PhiToReplacementMap, [](auto &KV) { return KV.second.isLookupTable(); });
+
+  // A few conditions prevent the generation of lookup tables:
+  //     1. The target does not support lookup tables.
+  //     2. The "no-jump-tables" function attribute is set.
+  // However, these objections do not apply to other switch replacements, like
+  // the bitmap, so we only stop here if any of these conditions are met and we
+  // want to create a LUT. Otherwise, continue with the switch replacement.
+  if (AnyLookupTables &&
+      (!TTI.shouldBuildLookupTables() ||
+       Fn->getFnAttribute("no-jump-tables").getValueAsBool()))
+    return false;
+
   Builder.SetInsertPoint(SI);
   // TableIndex is the switch condition - TableIndexOffset if we don't
   // use the condition directly
@@ -7219,7 +7234,6 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
   if (DTU)
     DTU->applyUpdates(Updates);
 
-  ++NumLookupTables;
   if (NeedMask)
     ++NumLookupTablesHoles;
   return true;

diff  --git a/llvm/test/Transforms/SimplifyCFG/switch-transformations-no-lut.ll b/llvm/test/Transforms/SimplifyCFG/switch-transformations-no-lut.ll
new file mode 100644
index 0000000000000..c9063d3ec26ff
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/switch-transformations-no-lut.ll
@@ -0,0 +1,515 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes='simplifycfg' < %s | FileCheck %s --check-prefix=OPTNOLUT
+; RUN: %if amdgpu-registered-target %{ opt -mtriple=amdgcn--amdpal -S -passes='simplifycfg<switch-to-lookup>' < %s | FileCheck %s --check-prefix=TTINOLUT %}
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i32 @linear_transform_with_default(i32 %x) {
+; OPTNOLUT-LABEL: define i32 @linear_transform_with_default(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[END:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[CASE0:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; OPTNOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; OPTNOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[CASE0]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE1]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE2]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE3]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[IDX:%.*]] = phi i32 [ 1, %[[CASE0]] ], [ 4, %[[CASE1]] ], [ 7, %[[CASE2]] ], [ 10, %[[CASE3]] ], [ 13, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i32 [[IDX]]
+;
+; TTINOLUT-LABEL: define i32 @linear_transform_with_default(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*]]:
+; TTINOLUT-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[X]], 4
+; TTINOLUT-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[END:.*]]
+; TTINOLUT:       [[SWITCH_LOOKUP]]:
+; TTINOLUT-NEXT:    [[SWITCH_IDX_MULT:%.*]] = mul nsw i32 [[X]], 3
+; TTINOLUT-NEXT:    [[SWITCH_OFFSET:%.*]] = add nsw i32 [[SWITCH_IDX_MULT]], 1
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[END]]:
+; TTINOLUT-NEXT:    [[IDX:%.*]] = phi i32 [ 13, %[[ENTRY]] ], [ [[SWITCH_OFFSET]], %[[SWITCH_LOOKUP]] ]
+; TTINOLUT-NEXT:    ret i32 [[IDX]]
+;
+entry:
+  switch i32 %x, label %end [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  ]
+
+case0:
+  br label %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+
+end:
+  %idx = phi i32 [ 1, %case0 ], [ 4, %case1 ], [ 7, %case2 ], [ 10, %case3 ], [ 13, %entry ]
+  ret i32 %idx
+}
+
+define i32 @linear_transform_with_outlier(i32 %x) {
+; OPTNOLUT-LABEL: define i32 @linear_transform_with_outlier(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[END:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[CASE0:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; OPTNOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; OPTNOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; OPTNOLUT-NEXT:      i32 4, label %[[CASE4:.*]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[CASE0]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE1]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE2]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE3]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE4]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[IDX:%.*]] = phi i32 [ 0, %[[CASE0]] ], [ 3, %[[CASE1]] ], [ 6, %[[CASE2]] ], [ 9, %[[CASE3]] ], [ 13, %[[CASE4]] ], [ 12, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i32 [[IDX]]
+;
+; TTINOLUT-LABEL: define i32 @linear_transform_with_outlier(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*]]:
+; TTINOLUT-NEXT:    switch i32 [[X]], label %[[END:.*]] [
+; TTINOLUT-NEXT:      i32 0, label %[[CASE0:.*]]
+; TTINOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; TTINOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; TTINOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; TTINOLUT-NEXT:      i32 4, label %[[CASE4:.*]]
+; TTINOLUT-NEXT:    ]
+; TTINOLUT:       [[CASE0]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[CASE1]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[CASE2]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[CASE3]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[CASE4]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[END]]:
+; TTINOLUT-NEXT:    [[IDX:%.*]] = phi i32 [ 0, %[[CASE0]] ], [ 3, %[[CASE1]] ], [ 6, %[[CASE2]] ], [ 9, %[[CASE3]] ], [ 13, %[[CASE4]] ], [ 12, %[[ENTRY]] ]
+; TTINOLUT-NEXT:    ret i32 [[IDX]]
+;
+entry:
+  switch i32 %x, label %end [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  i32 4, label %case4
+  ]
+
+case0:
+  br label %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+case4:
+  br label %end
+
+end:
+  %idx = phi i32 [ 0, %case0 ], [ 3, %case1 ], [ 6, %case2 ], [ 9, %case3 ], [ 13, %case4 ], [ 12, %entry ]
+  ret i32 %idx
+}
+
+define i32 @linear_transform_no_default(i32 %x) {
+; OPTNOLUT-LABEL: define i32 @linear_transform_no_default(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[DEFAULT:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[END:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; OPTNOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; OPTNOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; OPTNOLUT-NEXT:      i32 4, label %[[CASE4:.*]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[CASE1]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE2]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE3]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE4]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[DEFAULT]]:
+; OPTNOLUT-NEXT:    unreachable
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[SWITCH_IDX_MULT:%.*]] = phi i32 [ 3, %[[CASE1]] ], [ 6, %[[CASE2]] ], [ 9, %[[CASE3]] ], [ 12, %[[CASE4]] ], [ 0, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i32 [[SWITCH_IDX_MULT]]
+;
+; TTINOLUT-LABEL: define i32 @linear_transform_no_default(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*:]]
+; TTINOLUT-NEXT:    [[IDX:%.*]] = mul nsw i32 [[X]], 3
+; TTINOLUT-NEXT:    ret i32 [[IDX]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  i32 4, label %case4
+  ]
+
+case0:
+  br label %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+case4:
+  br label %end
+default:
+  unreachable
+
+end:
+  %idx = phi i32 [ 0, %case0 ], [ 3, %case1 ], [ 6, %case2 ], [ 9, %case3 ], [ 12, %case4 ]
+  ret i32 %idx
+}
+
+define i4 @bitmap_no_default(i32 %x) {
+; OPTNOLUT-LABEL: define i4 @bitmap_no_default(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[DEFAULT:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[END:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; OPTNOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; OPTNOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[CASE1]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE2]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE3]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[DEFAULT]]:
+; OPTNOLUT-NEXT:    unreachable
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[SWITCH_MASKED:%.*]] = phi i4 [ 2, %[[CASE1]] ], [ 4, %[[CASE2]] ], [ -8, %[[CASE3]] ], [ 0, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i4 [[SWITCH_MASKED]]
+;
+; TTINOLUT-LABEL: define i4 @bitmap_no_default(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*:]]
+; TTINOLUT-NEXT:    [[SWITCH_CAST:%.*]] = trunc i32 [[X]] to i16
+; TTINOLUT-NEXT:    [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i16 [[SWITCH_CAST]], 4
+; TTINOLUT-NEXT:    [[SWITCH_DOWNSHIFT:%.*]] = lshr i16 -31712, [[SWITCH_SHIFTAMT]]
+; TTINOLUT-NEXT:    [[IDX:%.*]] = trunc i16 [[SWITCH_DOWNSHIFT]] to i4
+; TTINOLUT-NEXT:    ret i4 [[IDX]]
+;
+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 %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+default:
+  unreachable
+
+end:
+  %idx = phi i4 [ 0, %case0 ], [ 2, %case1 ], [ 4, %case2 ], [ 8, %case3 ]
+  ret i4 %idx
+}
+
+define i4 @bitmap_with_default(i32 %x) {
+; OPTNOLUT-LABEL: define i4 @bitmap_with_default(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[DEFAULT:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[END:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; OPTNOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; OPTNOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[CASE1]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE2]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE3]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[DEFAULT]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[IDX:%.*]] = phi i4 [ 2, %[[CASE1]] ], [ 4, %[[CASE2]] ], [ -8, %[[CASE3]] ], [ -1, %[[DEFAULT]] ], [ 0, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i4 [[IDX]]
+;
+; TTINOLUT-LABEL: define i4 @bitmap_with_default(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*]]:
+; TTINOLUT-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[X]], 4
+; TTINOLUT-NEXT:    br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[END:.*]]
+; TTINOLUT:       [[SWITCH_LOOKUP]]:
+; TTINOLUT-NEXT:    [[SWITCH_CAST:%.*]] = trunc i32 [[X]] to i16
+; TTINOLUT-NEXT:    [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i16 [[SWITCH_CAST]], 4
+; TTINOLUT-NEXT:    [[SWITCH_DOWNSHIFT:%.*]] = lshr i16 -31712, [[SWITCH_SHIFTAMT]]
+; TTINOLUT-NEXT:    [[SWITCH_MASKED:%.*]] = trunc i16 [[SWITCH_DOWNSHIFT]] to i4
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[END]]:
+; TTINOLUT-NEXT:    [[IDX:%.*]] = phi i4 [ [[SWITCH_MASKED]], %[[SWITCH_LOOKUP]] ], [ -1, %[[ENTRY]] ]
+; TTINOLUT-NEXT:    ret i4 [[IDX]]
+;
+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 %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+default:
+  br label %end
+
+end:
+  %idx = phi i4 [ 0, %case0 ], [ 2, %case1 ], [ 4, %case2 ], [ 8, %case3 ], [15, %default]
+  ret i4 %idx
+}
+
+define i32 @single_value_no_default(i32 %x) {
+; OPTNOLUT-LABEL: define i32 @single_value_no_default(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*:]]
+; OPTNOLUT-NEXT:    ret i32 2
+;
+; TTINOLUT-LABEL: define i32 @single_value_no_default(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*:]]
+; TTINOLUT-NEXT:    ret i32 2
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  i32 4, label %case4
+  ]
+
+case0:
+  br label %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+case4:
+  br label %end
+default:
+  unreachable
+
+end:
+  %idx = phi i32 [ 2, %case0 ], [ 2, %case1 ], [ 2, %case2 ], [ 2, %case3 ], [ 2, %case4 ]
+  ret i32 %idx
+}
+
+define i32 @single_value_withdefault(i32 %x) {
+; OPTNOLUT-LABEL: define i32 @single_value_withdefault(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[DEFAULT:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[END:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[END]]
+; OPTNOLUT-NEXT:      i32 2, label %[[END]]
+; OPTNOLUT-NEXT:      i32 3, label %[[END]]
+; OPTNOLUT-NEXT:      i32 4, label %[[END]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[DEFAULT]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[DOT:%.*]] = phi i32 [ 3, %[[DEFAULT]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i32 [[DOT]]
+;
+; TTINOLUT-LABEL: define i32 @single_value_withdefault(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*:]]
+; TTINOLUT-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[X]], 5
+; TTINOLUT-NEXT:    [[IDX:%.*]] = select i1 [[TMP0]], i32 2, i32 3
+; TTINOLUT-NEXT:    ret i32 [[IDX]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  i32 4, label %case4
+  ]
+
+case0:
+  br label %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+case4:
+  br label %end
+default:
+  br label %end
+
+end:
+  %idx = phi i32 [ 2, %case0 ], [ 2, %case1 ], [ 2, %case2 ], [ 2, %case3 ], [ 2, %case4 ], [ 3, %default ]
+  ret i32 %idx
+}
+
+define i32 @single_value_no_jump_tables(i32 %x) "no-jump-tables"="true" {
+; OPTNOLUT-LABEL: define i32 @single_value_no_jump_tables(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[DEFAULT:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[END:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[END]]
+; OPTNOLUT-NEXT:      i32 2, label %[[END]]
+; OPTNOLUT-NEXT:      i32 3, label %[[END]]
+; OPTNOLUT-NEXT:      i32 4, label %[[END]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[DEFAULT]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[IDX:%.*]] = phi i32 [ 3, %[[DEFAULT]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ], [ 2, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i32 [[IDX]]
+;
+; TTINOLUT-LABEL: define i32 @single_value_no_jump_tables(
+; TTINOLUT-SAME: i32 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+; TTINOLUT-NEXT:  [[ENTRY:.*:]]
+; TTINOLUT-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[X]], 5
+; TTINOLUT-NEXT:    [[IDX:%.*]] = select i1 [[TMP0]], i32 2, i32 3
+; TTINOLUT-NEXT:    ret i32 [[IDX]]
+;
+entry:
+  switch i32 %x, label %default [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  i32 4, label %case4
+  ]
+
+case0:
+  br label %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+case4:
+  br label %end
+default:
+  br label %end
+
+end:
+  %idx = phi i32 [ 2, %case0 ], [ 2, %case1 ], [ 2, %case2 ], [ 2, %case3 ], [ 2, %case4 ], [ 3, %default ]
+  ret i32 %idx
+}
+
+define i32 @lookup_table(i32 %x) {
+; OPTNOLUT-LABEL: define i32 @lookup_table(
+; OPTNOLUT-SAME: i32 [[X:%.*]]) {
+; OPTNOLUT-NEXT:  [[ENTRY:.*]]:
+; OPTNOLUT-NEXT:    switch i32 [[X]], label %[[END:.*]] [
+; OPTNOLUT-NEXT:      i32 0, label %[[CASE0:.*]]
+; OPTNOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; OPTNOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; OPTNOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; OPTNOLUT-NEXT:    ]
+; OPTNOLUT:       [[CASE0]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE1]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE2]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[CASE3]]:
+; OPTNOLUT-NEXT:    br label %[[END]]
+; OPTNOLUT:       [[END]]:
+; OPTNOLUT-NEXT:    [[IDX:%.*]] = phi i32 [ 13, %[[CASE0]] ], [ 3, %[[CASE1]] ], [ 11, %[[CASE2]] ], [ 8, %[[CASE3]] ], [ 24, %[[ENTRY]] ]
+; OPTNOLUT-NEXT:    ret i32 [[IDX]]
+;
+; TTINOLUT-LABEL: define i32 @lookup_table(
+; TTINOLUT-SAME: i32 [[X:%.*]]) {
+; TTINOLUT-NEXT:  [[ENTRY:.*]]:
+; TTINOLUT-NEXT:    switch i32 [[X]], label %[[END:.*]] [
+; TTINOLUT-NEXT:      i32 0, label %[[CASE0:.*]]
+; TTINOLUT-NEXT:      i32 1, label %[[CASE1:.*]]
+; TTINOLUT-NEXT:      i32 2, label %[[CASE2:.*]]
+; TTINOLUT-NEXT:      i32 3, label %[[CASE3:.*]]
+; TTINOLUT-NEXT:    ]
+; TTINOLUT:       [[CASE0]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[CASE1]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[CASE2]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[CASE3]]:
+; TTINOLUT-NEXT:    br label %[[END]]
+; TTINOLUT:       [[END]]:
+; TTINOLUT-NEXT:    [[IDX:%.*]] = phi i32 [ 13, %[[CASE0]] ], [ 3, %[[CASE1]] ], [ 11, %[[CASE2]] ], [ 8, %[[CASE3]] ], [ 24, %[[ENTRY]] ]
+; TTINOLUT-NEXT:    ret i32 [[IDX]]
+;
+entry:
+  switch i32 %x, label %end [
+  i32 0, label %case0
+  i32 1, label %case1
+  i32 2, label %case2
+  i32 3, label %case3
+  ]
+
+case0:
+  br label %end
+case1:
+  br label %end
+case2:
+  br label %end
+case3:
+  br label %end
+
+end:
+  %idx = phi i32 [ 13, %case0 ], [ 3, %case1 ], [ 11, %case2 ], [ 8, %case3 ], [ 24, %entry ]
+  ret i32 %idx
+}


        


More information about the llvm-commits mailing list