[llvm] [NFC] SimplifyCFG: Detect switch replacement earlier in `switchToLookup` (PR #155602)

Jessica Del via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 27 05:00:09 PDT 2025


https://github.com/OutOfCache created https://github.com/llvm/llvm-project/pull/155602

This PR is the first part to solve the issue in #149937.

The end goal is enabling more switch optimizations on targets that do not support lookup tables.

SimplifyCFG has the ability to replace switches with either a few simple calculations, a single value, or a lookup table.
However, it only considers these options if the target supports lookup tables, even if the final result is not a LUT, but a few simple instructions like muls, adds and shifts.

To enable more targets to use these other kinds of optimization, this PR restructures the code in `switchToLookup`.
Previously, code was generated even before choosing what kind of replacement to do. However, we need to know if we actually want to create a true LUT or not before generating anything. Then we can check for target support only if any LUT would be created.

This PR moves the code so it first determines the replacement kind and then generates the instructions.

A later PR will insert the target support check after determining the kind of replacement. If the result is not a LUT, then even targets without LUT support can replace the switch with something else.

>From 6cf88f97cf43259939ce9a221fdbcd087fc09edb Mon Sep 17 00:00:00 2001
From: Jessica Del <Jessica.Del at amd.com>
Date: Tue, 26 Aug 2025 16:03:11 +0200
Subject: [PATCH 1/6] SimplifyCFG: Move ResultType and NumResults calculation

Move the insertion into ResultTypes further up and the NumResults
further down.
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index ef110a6922f05..49426db175f4d 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6955,7 +6955,8 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
                         Results, DL, TTI))
       return false;
 
-    // Append the result from this case to the list for each phi.
+    // Append the result  and result types from this case to the list for each
+    // phi.
     for (const auto &I : Results) {
       PHINode *PHI = I.first;
       Constant *Value = I.second;
@@ -6963,23 +6964,16 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
       if (Inserted)
         PHIs.push_back(PHI);
       It->second.push_back(std::make_pair(CaseVal, Value));
+      ResultTypes[PHI] = ResultLists[PHI][0].second->getType();
     }
   }
 
-  // Keep track of the result types.
-  for (PHINode *PHI : PHIs) {
-    ResultTypes[PHI] = ResultLists[PHI][0].second->getType();
-  }
-
-  uint64_t NumResults = ResultLists[PHIs[0]].size();
-
   // 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);
-
   for (const auto &I : DefaultResultsList) {
     PHINode *PHI = I.first;
     Constant *Result = I.second;
@@ -6998,6 +6992,7 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
   // If the default destination is unreachable, or if the lookup table covers
   // all values of the conditional variable, branch directly to the lookup table
   // BB. Otherwise, check that the condition is within the case range.
+  uint64_t NumResults = ResultLists[PHIs[0]].size();
   bool DefaultIsReachable = !SI->defaultDestUnreachable();
 
   bool TableHasHoles = (NumResults < TableSize);

>From ee5a80d2882e3bfc82f35fd3687a25ea0c749a1f Mon Sep 17 00:00:00 2001
From: Jessica Del <Jessica.Del at amd.com>
Date: Tue, 26 Aug 2025 16:06:14 +0200
Subject: [PATCH 2/6] SimplifyCFG: Calculate TableIndexOffset earlier

---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 49426db175f4d..1ec292b2257b1 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6983,12 +6983,17 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
   bool UseSwitchConditionAsTableIndex = shouldUseSwitchConditionAsTableIndex(
       *MinCaseVal, *MaxCaseVal, HasDefaultResults, ResultTypes, DL, TTI);
   uint64_t TableSize;
-  if (UseSwitchConditionAsTableIndex)
+  ConstantInt *TableIndexOffset;
+  if (UseSwitchConditionAsTableIndex) {
     TableSize = MaxCaseVal->getLimitedValue() + 1;
-  else
+    TableIndexOffset = ConstantInt::get(MaxCaseVal->getIntegerType(), 0);
+  } else {
     TableSize =
         (MaxCaseVal->getValue() - MinCaseVal->getValue()).getLimitedValue() + 1;
 
+    TableIndexOffset = MinCaseVal;
+  }
+
   // If the default destination is unreachable, or if the lookup table covers
   // all values of the conditional variable, branch directly to the lookup table
   // BB. Otherwise, check that the condition is within the case range.
@@ -7038,12 +7043,9 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
   // Compute the table index value.
   Builder.SetInsertPoint(SI);
   Value *TableIndex;
-  ConstantInt *TableIndexOffset;
   if (UseSwitchConditionAsTableIndex) {
-    TableIndexOffset = ConstantInt::get(MaxCaseVal->getIntegerType(), 0);
     TableIndex = SI->getCondition();
   } else {
-    TableIndexOffset = MinCaseVal;
     // If the default is unreachable, all case values are s>= MinCaseVal. Then
     // we can try to attach nsw.
     bool MayWrap = true;

>From b25f19765e48698e2f2a63bd46e6a74a4ad10865 Mon Sep 17 00:00:00 2001
From: Jessica Del <Jessica.Del at amd.com>
Date: Tue, 26 Aug 2025 16:25:31 +0200
Subject: [PATCH 3/6] SimplifyCFG: Move TableIndex further up to calculate
 TableSize earlier

If we use the switch condition as table index, the default results
can influence the TableSize.
The TableSize is used for the decision whether we want to create a table
in the first place, so it makes sense to set TableIndex and the final
TableSize before the check in `shouldBuildLookupTable`.

However, if we do not use the switch condition as the table index,
we move the setting *after* the decision to build it.
Since we need to create a sub instruction in that case, only do that
once we are sure. Additionally, that case does not influence the
TableSize, so there is no harm in setting it later.
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 89 ++++++++++++-----------
 1 file changed, 47 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 1ec292b2257b1..82902ce503ba2 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -7022,9 +7022,55 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
       return false;
   }
 
+  // Compute the table index value.
+  Value *TableIndex;
+  if (UseSwitchConditionAsTableIndex) {
+    TableIndex = SI->getCondition();
+    if (HasDefaultResults) {
+      // Grow the table to cover all possible index values to avoid the range
+      // check. It will use the default result to fill in the table hole later,
+      // so make sure it exist.
+      ConstantRange CR =
+          computeConstantRange(TableIndex, /* ForSigned */ false);
+      // Grow the table shouldn't have any size impact by checking
+      // wouldFitInRegister.
+      // TODO: Consider growing the table also when it doesn't fit in a register
+      // if no optsize is specified.
+      const uint64_t UpperBound = CR.getUpper().getLimitedValue();
+      if (!CR.isUpperWrapped() && all_of(ResultTypes, [&](const auto &KV) {
+            return SwitchLookupTable::wouldFitInRegister(
+                DL, UpperBound, KV.second /* ResultType */);
+          })) {
+        // There may be some case index larger than the UpperBound (unreachable
+        // case), so make sure the table size does not get smaller.
+        TableSize = std::max(UpperBound, TableSize);
+        // The default branch is unreachable after we enlarge the lookup table.
+        // Adjust DefaultIsReachable to reuse code path.
+        DefaultIsReachable = false;
+      }
+    }
+  }
+
   if (!shouldBuildLookupTable(SI, TableSize, TTI, DL, ResultTypes))
     return false;
 
+  Builder.SetInsertPoint(SI);
+  // TableIndex is the switch condition - TableIndexOffset if we don't
+  // use the condition directly
+  if (!UseSwitchConditionAsTableIndex) {
+    // If the default is unreachable, all case values are s>= MinCaseVal. Then
+    // we can try to attach nsw.
+    bool MayWrap = true;
+    if (!DefaultIsReachable) {
+      APInt Res =
+          MaxCaseVal->getValue().ssub_ov(MinCaseVal->getValue(), MayWrap);
+      (void)Res;
+    }
+    TableIndex = Builder.CreateSub(SI->getCondition(), TableIndexOffset,
+                                   "switch.tableidx", /*HasNUW =*/false,
+                                   /*HasNSW =*/!MayWrap);
+  }
+
   std::vector<DominatorTree::UpdateType> Updates;
 
   // Compute the maximum table size representable by the integer type we are
@@ -7040,50 +7086,9 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
   BasicBlock *LookupBB = BasicBlock::Create(
       Mod.getContext(), "switch.lookup", CommonDest->getParent(), CommonDest);
 
-  // Compute the table index value.
-  Builder.SetInsertPoint(SI);
-  Value *TableIndex;
-  if (UseSwitchConditionAsTableIndex) {
-    TableIndex = SI->getCondition();
-  } else {
-    // If the default is unreachable, all case values are s>= MinCaseVal. Then
-    // we can try to attach nsw.
-    bool MayWrap = true;
-    if (!DefaultIsReachable) {
-      APInt Res = MaxCaseVal->getValue().ssub_ov(MinCaseVal->getValue(), MayWrap);
-      (void)Res;
-    }
-
-    TableIndex = Builder.CreateSub(SI->getCondition(), TableIndexOffset,
-                                   "switch.tableidx", /*HasNUW =*/false,
-                                   /*HasNSW =*/!MayWrap);
-  }
-
   BranchInst *RangeCheckBranch = nullptr;
 
-  // Grow the table to cover all possible index values to avoid the range check.
-  // It will use the default result to fill in the table hole later, so make
-  // sure it exist.
-  if (UseSwitchConditionAsTableIndex && HasDefaultResults) {
-    ConstantRange CR = computeConstantRange(TableIndex, /* ForSigned */ false);
-    // Grow the table shouldn't have any size impact by checking
-    // wouldFitInRegister.
-    // TODO: Consider growing the table also when it doesn't fit in a register
-    // if no optsize is specified.
-    const uint64_t UpperBound = CR.getUpper().getLimitedValue();
-    if (!CR.isUpperWrapped() && all_of(ResultTypes, [&](const auto &KV) {
-          return SwitchLookupTable::wouldFitInRegister(
-              DL, UpperBound, KV.second /* ResultType */);
-        })) {
-      // There may be some case index larger than the UpperBound (unreachable
-      // case), so make sure the table size does not get smaller.
-      TableSize = std::max(UpperBound, TableSize);
-      // The default branch is unreachable after we enlarge the lookup table.
-      // Adjust DefaultIsReachable to reuse code path.
-      DefaultIsReachable = false;
-    }
-  }
-
+  Builder.SetInsertPoint(SI);
   const bool GeneratingCoveredLookupTable = (MaxTableSize == TableSize);
   if (!DefaultIsReachable || GeneratingCoveredLookupTable) {
     Builder.CreateBr(LookupBB);

>From efa2d5c7e77e55662c47915ed383c0fe4724c7a3 Mon Sep 17 00:00:00 2001
From: Jessica Del <Jessica.Del at amd.com>
Date: Tue, 26 Aug 2025 16:41:24 +0200
Subject: [PATCH 4/6] SimplifyCFG: Create the SwitchLookupTable earlier

The table decides what kind of lookup table is created. To become more
flexible in a future change, we want to know the type before we check if
we want to create it.
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 38 +++++++++++++++--------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 82902ce503ba2..6e7eb69543b3e 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -7071,6 +7071,27 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
                                    /*HasNSW =*/!MayWrap);
   }
 
+  // Keep track of the tables we create for each phi node
+  struct TableInfo {
+    SwitchLookupTable Table;
+    Constant *DefaultValue;
+  };
+  // Find out what kind of table to create by creating a SwitchLookupTable
+  SmallDenseMap<PHINode *, TableInfo> PhiToTableMap;
+  for (PHINode *PHI : PHIs) {
+    const auto &ResultList = ResultLists[PHI];
+
+    Type *ResultType = ResultList.begin()->second->getType();
+    // Use any value to fill the lookup table holes.
+    Constant *DV =
+        AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
+    StringRef FuncName = Fn->getName();
+    SwitchLookupTable Table(*Fn->getParent(), TableSize, TableIndexOffset,
+                            ResultList, DV, DL, FuncName);
+    TableInfo TI = {Table, DV};
+    PhiToTableMap.insert({PHI, TI});
+  }
+
   std::vector<DominatorTree::UpdateType> Updates;
 
   // Compute the maximum table size representable by the integer type we are
@@ -7159,25 +7180,16 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
 
   for (PHINode *PHI : PHIs) {
     const ResultListTy &ResultList = ResultLists[PHI];
-
-    Type *ResultType = ResultList.begin()->second->getType();
-
-    // Use any value to fill the lookup table holes.
-    Constant *DV =
-        AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
-    StringRef FuncName = Fn->getName();
-    SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV,
-                            DL, FuncName);
-
-    Value *Result = Table.buildLookup(TableIndex, Builder, DL);
-
+    auto TableInfo = PhiToTableMap.at(PHI);
+    auto *Result = TableInfo.Table.buildLookup(TableIndex, Builder, DL);
     // Do a small peephole optimization: re-use the switch table compare if
     // possible.
     if (!TableHasHoles && HasDefaultResults && RangeCheckBranch) {
       BasicBlock *PhiBlock = PHI->getParent();
       // Search for compare instructions which use the phi.
       for (auto *User : PHI->users()) {
-        reuseTableCompare(User, PhiBlock, RangeCheckBranch, DV, ResultList);
+        reuseTableCompare(User, PhiBlock, RangeCheckBranch,
+                          TableInfo.DefaultValue, ResultList);
       }
     }
 

>From 86419f7dda90388ef6057a3765d1b73cfddce519 Mon Sep 17 00:00:00 2001
From: Jessica Del <Jessica.Del at amd.com>
Date: Tue, 26 Aug 2025 15:21:04 +0200
Subject: [PATCH 5/6] SimplifyCFG: Delay lookup table creation

Previously, the global LUT was created in the constructor of
SwitchLookupTable.
Since we want to call the constructor way earlier to decide what kind of
LUT to create (and if we want to create any), this can create the LUT
unnecessarily if we later on decide not to use one.
Only create it once we are certain we want to create a LUT.
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 36 ++++++++++++++---------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 6e7eb69543b3e..0dfbf4784ffc2 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6449,7 +6449,8 @@ class SwitchLookupTable {
 
   /// Build instructions with Builder to retrieve the value at
   /// the position given by Index in the lookup table.
-  Value *buildLookup(Value *Index, IRBuilder<> &Builder, const DataLayout &DL);
+  Value *buildLookup(Value *Index, IRBuilder<> &Builder, const DataLayout &DL,
+                     Function *Func);
 
   /// Return true if a table with TableSize elements of
   /// type ElementType would fit in a target-legal register.
@@ -6479,6 +6480,9 @@ class SwitchLookupTable {
     ArrayKind
   } Kind;
 
+  // The type of the output values.
+  Type *ValueType;
+
   // For SingleValueKind, this is the single value.
   Constant *SingleValue = nullptr;
 
@@ -6493,6 +6497,8 @@ class SwitchLookupTable {
 
   // For ArrayKind, this is the array.
   GlobalVariable *Array = nullptr;
+  ArrayType *ArrayTy = nullptr;
+  Constant *Initializer = nullptr;
 };
 
 } // end anonymous namespace
@@ -6507,7 +6513,7 @@ SwitchLookupTable::SwitchLookupTable(
   // If all values in the table are equal, this is that value.
   SingleValue = Values.begin()->second;
 
-  Type *ValueType = Values.begin()->second->getType();
+  ValueType = Values.begin()->second->getType();
 
   // Build up the table contents.
   SmallVector<Constant *, 64> TableContents(TableSize);
@@ -6622,21 +6628,14 @@ SwitchLookupTable::SwitchLookupTable(
   }
 
   // Store the table in an array.
-  ArrayType *ArrayTy = ArrayType::get(ValueType, TableSize);
-  Constant *Initializer = ConstantArray::get(ArrayTy, TableContents);
-
-  Array = new GlobalVariable(M, ArrayTy, /*isConstant=*/true,
-                             GlobalVariable::PrivateLinkage, Initializer,
-                             "switch.table." + FuncName);
-  Array->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
-  // Set the alignment to that of an array items. We will be only loading one
-  // value out of it.
-  Array->setAlignment(DL.getPrefTypeAlign(ValueType));
+  ArrayTy = ArrayType::get(ValueType, TableSize);
+  Initializer = ConstantArray::get(ArrayTy, TableContents);
+
   Kind = ArrayKind;
 }
 
 Value *SwitchLookupTable::buildLookup(Value *Index, IRBuilder<> &Builder,
-                                      const DataLayout &DL) {
+                                      const DataLayout &DL, Function *Func) {
   switch (Kind) {
   case SingleValueKind:
     return SingleValue;
@@ -6678,6 +6677,15 @@ Value *SwitchLookupTable::buildLookup(Value *Index, IRBuilder<> &Builder,
     return Builder.CreateTrunc(DownShifted, BitMapElementTy, "switch.masked");
   }
   case ArrayKind: {
+    // Only build lookup table when we have a target that supports it or the
+    // attribute is not set.
+    Array = new GlobalVariable(*Func->getParent(), ArrayTy, /*isConstant=*/true,
+                               GlobalVariable::PrivateLinkage, Initializer,
+                               "switch.table." + Func->getName());
+    Array->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+    // Set the alignment to that of an array items. We will be only loading one
+    // value out of it.
+    Array->setAlignment(DL.getPrefTypeAlign(ValueType));
     Type *IndexTy = DL.getIndexType(Array->getType());
     auto *ArrayTy = cast<ArrayType>(Array->getValueType());
 
@@ -7181,7 +7189,7 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
   for (PHINode *PHI : PHIs) {
     const ResultListTy &ResultList = ResultLists[PHI];
     auto TableInfo = PhiToTableMap.at(PHI);
-    auto *Result = TableInfo.Table.buildLookup(TableIndex, Builder, DL);
+    auto *Result = TableInfo.Table.buildLookup(TableIndex, Builder, DL, Fn);
     // Do a small peephole optimization: re-use the switch table compare if
     // possible.
     if (!TableHasHoles && HasDefaultResults && RangeCheckBranch) {

>From 8490b44b1f68f2fb57ddcf81d04d89e35af664c4 Mon Sep 17 00:00:00 2001
From: Jessica Del <Jessica.Del at amd.com>
Date: Tue, 26 Aug 2025 16:57:25 +0200
Subject: [PATCH 6/6] SimplifyCFG: Renaming

SwitchLookupTable -> SwitchReplacement
This class contains more than just a typical lookup table.
It helps to optimize the switch away, either by lookup table, or with a
linear function, a bitmap, or a single value replacement.

ArrayKind -> LookupTableKind
ArrayKind is the "true" LUT kind.

buildLookup -> replaceSwitch
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 108 +++++++++++-----------
 1 file changed, 55 insertions(+), 53 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 0dfbf4784ffc2..a8bae3f99746a 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6437,20 +6437,22 @@ static bool trySwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder,
 
 namespace {
 
-/// This class represents a lookup table that can be used to replace a switch.
-class SwitchLookupTable {
+/// This class finds alternatives for switches to ultimately
+/// replace the switch.
+class SwitchReplacement {
 public:
-  /// Create a lookup table to use as a switch replacement with the contents
-  /// of Values, using DefaultValue to fill any holes in the table.
-  SwitchLookupTable(
+  /// 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.
+  SwitchReplacement(
       Module &M, uint64_t TableSize, ConstantInt *Offset,
       const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
       Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName);
 
-  /// Build instructions with Builder to retrieve the value at
-  /// the position given by Index in the lookup table.
-  Value *buildLookup(Value *Index, IRBuilder<> &Builder, const DataLayout &DL,
-                     Function *Func);
+  /// Build instructions with Builder to retrieve values using Index
+  /// and replace the switch.
+  Value *replaceSwitch(Value *Index, IRBuilder<> &Builder, const DataLayout &DL,
+                       Function *Func);
 
   /// Return true if a table with TableSize elements of
   /// type ElementType would fit in a target-legal register.
@@ -6458,14 +6460,13 @@ class SwitchLookupTable {
                                  Type *ElementType);
 
 private:
-  // Depending on the contents of the table, it can be represented in
-  // different ways.
+  // Depending on the switch, there are different alternatives.
   enum {
-    // For tables where each element contains the same value, we just have to
+    // For switches where each case contains the same value, we just have to
     // store that single value and return it for each lookup.
     SingleValueKind,
 
-    // For tables where there is a linear relationship between table index
+    // For switches where there is a linear relationship between table index
     // and values. We calculate the result with a simple multiplication
     // and addition instead of a table lookup.
     LinearMapKind,
@@ -6477,7 +6478,7 @@ class SwitchLookupTable {
 
     // The table is stored as an array of values. Values are retrieved by load
     // instructions from the table.
-    ArrayKind
+    LookupTableKind
   } Kind;
 
   // The type of the output values.
@@ -6495,15 +6496,15 @@ class SwitchLookupTable {
   ConstantInt *LinearMultiplier = nullptr;
   bool LinearMapValWrapped = false;
 
-  // For ArrayKind, this is the array.
-  GlobalVariable *Array = nullptr;
-  ArrayType *ArrayTy = nullptr;
+  // For LookupTableKind, this is the table.
+  GlobalVariable *Table = nullptr;
+  ArrayType *TableTy = nullptr;
   Constant *Initializer = nullptr;
 };
 
 } // end anonymous namespace
 
-SwitchLookupTable::SwitchLookupTable(
+SwitchReplacement::SwitchReplacement(
     Module &M, uint64_t TableSize, ConstantInt *Offset,
     const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
     Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName) {
@@ -6628,14 +6629,14 @@ SwitchLookupTable::SwitchLookupTable(
   }
 
   // Store the table in an array.
-  ArrayTy = ArrayType::get(ValueType, TableSize);
-  Initializer = ConstantArray::get(ArrayTy, TableContents);
+  TableTy = ArrayType::get(ValueType, TableSize);
+  Initializer = ConstantArray::get(TableTy, TableContents);
 
-  Kind = ArrayKind;
+  Kind = LookupTableKind;
 }
 
-Value *SwitchLookupTable::buildLookup(Value *Index, IRBuilder<> &Builder,
-                                      const DataLayout &DL, Function *Func) {
+Value *SwitchReplacement::replaceSwitch(Value *Index, IRBuilder<> &Builder,
+                                        const DataLayout &DL, Function *Func) {
   switch (Kind) {
   case SingleValueKind:
     return SingleValue;
@@ -6676,18 +6677,18 @@ Value *SwitchLookupTable::buildLookup(Value *Index, IRBuilder<> &Builder,
     // Mask off.
     return Builder.CreateTrunc(DownShifted, BitMapElementTy, "switch.masked");
   }
-  case ArrayKind: {
+  case LookupTableKind: {
     // Only build lookup table when we have a target that supports it or the
-    // attribute is not set.
-    Array = new GlobalVariable(*Func->getParent(), ArrayTy, /*isConstant=*/true,
+    // attribute is notable.
+    Table = new GlobalVariable(*Func->getParent(), TableTy, /*isConstant=*/true,
                                GlobalVariable::PrivateLinkage, Initializer,
                                "switch.table." + Func->getName());
-    Array->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+    Table->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
     // Set the alignment to that of an array items. We will be only loading one
     // value out of it.
-    Array->setAlignment(DL.getPrefTypeAlign(ValueType));
-    Type *IndexTy = DL.getIndexType(Array->getType());
-    auto *ArrayTy = cast<ArrayType>(Array->getValueType());
+    Table->setAlignment(DL.getPrefTypeAlign(ValueType));
+    Type *IndexTy = DL.getIndexType(Table->getType());
+    auto *ArrayTy = cast<ArrayType>(Table->getValueType());
 
     if (Index->getType() != IndexTy) {
       unsigned OldBitWidth = Index->getType()->getIntegerBitWidth();
@@ -6699,14 +6700,14 @@ Value *SwitchLookupTable::buildLookup(Value *Index, IRBuilder<> &Builder,
 
     Value *GEPIndices[] = {ConstantInt::get(IndexTy, 0), Index};
     Value *GEP =
-        Builder.CreateInBoundsGEP(ArrayTy, Array, GEPIndices, "switch.gep");
+        Builder.CreateInBoundsGEP(ArrayTy, Table, GEPIndices, "switch.gep");
     return Builder.CreateLoad(ArrayTy->getElementType(), GEP, "switch.load");
   }
   }
-  llvm_unreachable("Unknown lookup table kind!");
+  llvm_unreachable("Unknown helper kind!");
 }
 
-bool SwitchLookupTable::wouldFitInRegister(const DataLayout &DL,
+bool SwitchReplacement::wouldFitInRegister(const DataLayout &DL,
                                            uint64_t TableSize,
                                            Type *ElementType) {
   auto *IT = dyn_cast<IntegerType>(ElementType);
@@ -6786,7 +6787,7 @@ shouldBuildLookupTable(SwitchInst *SI, uint64_t TableSize,
     // Saturate this flag to false.
     AllTablesFitInRegister =
         AllTablesFitInRegister &&
-        SwitchLookupTable::wouldFitInRegister(DL, TableSize, Ty);
+        SwitchReplacement::wouldFitInRegister(DL, TableSize, Ty);
 
     // If both flags saturate, we're done. NOTE: This *only* works with
     // saturating flags, and all flags have to saturate first due to the
@@ -6817,7 +6818,7 @@ static bool shouldUseSwitchConditionAsTableIndex(
       !HasDefaultResults)
     return false;
   return all_of(ResultTypes, [&](const auto &KV) {
-    return SwitchLookupTable::wouldFitInRegister(
+    return SwitchReplacement::wouldFitInRegister(
         DL, MaxCaseVal.getLimitedValue() + 1 /* TableSize */,
         KV.second /* ResultType */);
   });
@@ -6908,9 +6909,9 @@ static void reuseTableCompare(
 /// If the switch is only used to initialize one or more phi nodes in a common
 /// successor block with different constant values, replace the switch with
 /// lookup tables.
-static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
-                                DomTreeUpdater *DTU, const DataLayout &DL,
-                                const TargetTransformInfo &TTI) {
+static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
+                                   DomTreeUpdater *DTU, const DataLayout &DL,
+                                   const TargetTransformInfo &TTI) {
   assert(SI->getNumCases() > 1 && "Degenerate switch?");
 
   BasicBlock *BB = SI->getParent();
@@ -7046,7 +7047,7 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
       // if no optsize is specified.
       const uint64_t UpperBound = CR.getUpper().getLimitedValue();
       if (!CR.isUpperWrapped() && all_of(ResultTypes, [&](const auto &KV) {
-            return SwitchLookupTable::wouldFitInRegister(
+            return SwitchReplacement::wouldFitInRegister(
                 DL, UpperBound, KV.second /* ResultType */);
           })) {
         // There may be some case index larger than the UpperBound (unreachable
@@ -7080,24 +7081,24 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
   }
 
   // Keep track of the tables we create for each phi node
-  struct TableInfo {
-    SwitchLookupTable Table;
-    Constant *DefaultValue;
+  struct ReplacementParams {
+    SwitchReplacement Replacer;
+    Constant *DefaultVal;
   };
-  // Find out what kind of table to create by creating a SwitchLookupTable
-  SmallDenseMap<PHINode *, TableInfo> PhiToTableMap;
+  // Keep track of the switch replacement for each phi
+  SmallDenseMap<PHINode *, ReplacementParams> PhiToReplacementMap;
   for (PHINode *PHI : PHIs) {
     const auto &ResultList = ResultLists[PHI];
 
     Type *ResultType = ResultList.begin()->second->getType();
     // Use any value to fill the lookup table holes.
-    Constant *DV =
+    Constant *DefaultVal =
         AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
     StringRef FuncName = Fn->getName();
-    SwitchLookupTable Table(*Fn->getParent(), TableSize, TableIndexOffset,
-                            ResultList, DV, DL, FuncName);
-    TableInfo TI = {Table, DV};
-    PhiToTableMap.insert({PHI, TI});
+    SwitchReplacement Replacement(*Fn->getParent(), TableSize, TableIndexOffset,
+                                  ResultList, DefaultVal, DL, FuncName);
+    ReplacementParams Parameters = {Replacement, DefaultVal};
+    PhiToReplacementMap.insert({PHI, Parameters});
   }
 
   std::vector<DominatorTree::UpdateType> Updates;
@@ -7188,8 +7189,9 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
 
   for (PHINode *PHI : PHIs) {
     const ResultListTy &ResultList = ResultLists[PHI];
-    auto TableInfo = PhiToTableMap.at(PHI);
-    auto *Result = TableInfo.Table.buildLookup(TableIndex, Builder, DL, Fn);
+    auto TableInfo = PhiToReplacementMap.at(PHI);
+    auto *Result =
+        TableInfo.Replacer.replaceSwitch(TableIndex, Builder, DL, Fn);
     // Do a small peephole optimization: re-use the switch table compare if
     // possible.
     if (!TableHasHoles && HasDefaultResults && RangeCheckBranch) {
@@ -7197,7 +7199,7 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
       // Search for compare instructions which use the phi.
       for (auto *User : PHI->users()) {
         reuseTableCompare(User, PhiBlock, RangeCheckBranch,
-                          TableInfo.DefaultValue, ResultList);
+                          TableInfo.DefaultVal, ResultList);
       }
     }
 
@@ -7730,7 +7732,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
   // CVP. Therefore, only apply this transformation during late stages of the
   // optimisation pipeline.
   if (Options.ConvertSwitchToLookupTable &&
-      switchToLookupTable(SI, Builder, DTU, DL, TTI))
+      simplifySwitchLookup(SI, Builder, DTU, DL, TTI))
     return requestResimplify();
 
   if (simplifySwitchOfPowersOfTwo(SI, Builder, DL, TTI))



More information about the llvm-commits mailing list