1829037a9SAmara Emerson //===- SwitchLoweringUtils.cpp - Switch Lowering --------------------------===// 2829037a9SAmara Emerson // 3829037a9SAmara Emerson // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4829037a9SAmara Emerson // See https://llvm.org/LICENSE.txt for license information. 5829037a9SAmara Emerson // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6829037a9SAmara Emerson // 7829037a9SAmara Emerson //===----------------------------------------------------------------------===// 8829037a9SAmara Emerson // 9829037a9SAmara Emerson // This file contains switch inst lowering optimizations and utilities for 10829037a9SAmara Emerson // codegen, so that it can be used for both SelectionDAG and GlobalISel. 11829037a9SAmara Emerson // 12829037a9SAmara Emerson //===----------------------------------------------------------------------===// 13829037a9SAmara Emerson 14829037a9SAmara Emerson #include "llvm/CodeGen/SwitchLoweringUtils.h" 15*1673a080SSimon Pilgrim #include "llvm/CodeGen/FunctionLoweringInfo.h" 16*1673a080SSimon Pilgrim #include "llvm/CodeGen/MachineJumpTableInfo.h" 17fe0006c8SSimon Pilgrim #include "llvm/Target/TargetMachine.h" 18829037a9SAmara Emerson 19829037a9SAmara Emerson using namespace llvm; 20829037a9SAmara Emerson using namespace SwitchCG; 21829037a9SAmara Emerson 223740ae3bSHans Wennborg uint64_t SwitchCG::getJumpTableRange(const CaseClusterVector &Clusters, 233740ae3bSHans Wennborg unsigned First, unsigned Last) { 243740ae3bSHans Wennborg assert(Last >= First); 253740ae3bSHans Wennborg const APInt &LowCase = Clusters[First].Low->getValue(); 263740ae3bSHans Wennborg const APInt &HighCase = Clusters[Last].High->getValue(); 273740ae3bSHans Wennborg assert(LowCase.getBitWidth() == HighCase.getBitWidth()); 28829037a9SAmara Emerson 293740ae3bSHans Wennborg // FIXME: A range of consecutive cases has 100% density, but only requires one 303740ae3bSHans Wennborg // comparison to lower. We should discriminate against such consecutive ranges 313740ae3bSHans Wennborg // in jump tables. 323740ae3bSHans Wennborg return (HighCase - LowCase).getLimitedValue((UINT64_MAX - 1) / 100) + 1; 33829037a9SAmara Emerson } 34829037a9SAmara Emerson 353740ae3bSHans Wennborg uint64_t 363740ae3bSHans Wennborg SwitchCG::getJumpTableNumCases(const SmallVectorImpl<unsigned> &TotalCases, 373740ae3bSHans Wennborg unsigned First, unsigned Last) { 383740ae3bSHans Wennborg assert(Last >= First); 393740ae3bSHans Wennborg assert(TotalCases[Last] >= TotalCases[First]); 403740ae3bSHans Wennborg uint64_t NumCases = 413740ae3bSHans Wennborg TotalCases[Last] - (First == 0 ? 0 : TotalCases[First - 1]); 423740ae3bSHans Wennborg return NumCases; 43829037a9SAmara Emerson } 44829037a9SAmara Emerson 45829037a9SAmara Emerson void SwitchCG::SwitchLowering::findJumpTables(CaseClusterVector &Clusters, 46829037a9SAmara Emerson const SwitchInst *SI, 470d987e41SHiroshi Yamauchi MachineBasicBlock *DefaultMBB, 480d987e41SHiroshi Yamauchi ProfileSummaryInfo *PSI, 490d987e41SHiroshi Yamauchi BlockFrequencyInfo *BFI) { 50829037a9SAmara Emerson #ifndef NDEBUG 51829037a9SAmara Emerson // Clusters must be non-empty, sorted, and only contain Range clusters. 52829037a9SAmara Emerson assert(!Clusters.empty()); 53829037a9SAmara Emerson for (CaseCluster &C : Clusters) 54829037a9SAmara Emerson assert(C.Kind == CC_Range); 55829037a9SAmara Emerson for (unsigned i = 1, e = Clusters.size(); i < e; ++i) 56829037a9SAmara Emerson assert(Clusters[i - 1].High->getValue().slt(Clusters[i].Low->getValue())); 57829037a9SAmara Emerson #endif 58829037a9SAmara Emerson 59fe4625fbSAmara Emerson assert(TLI && "TLI not set!"); 60829037a9SAmara Emerson if (!TLI->areJTsAllowed(SI->getParent()->getParent())) 61829037a9SAmara Emerson return; 62829037a9SAmara Emerson 63829037a9SAmara Emerson const unsigned MinJumpTableEntries = TLI->getMinimumJumpTableEntries(); 64829037a9SAmara Emerson const unsigned SmallNumberOfEntries = MinJumpTableEntries / 2; 65829037a9SAmara Emerson 66aa10f050SEvandro Menezes // Bail if not enough cases. 67aa10f050SEvandro Menezes const int64_t N = Clusters.size(); 68829037a9SAmara Emerson if (N < 2 || N < MinJumpTableEntries) 69829037a9SAmara Emerson return; 70829037a9SAmara Emerson 713740ae3bSHans Wennborg // Accumulated number of cases in each cluster and those prior to it. 723740ae3bSHans Wennborg SmallVector<unsigned, 8> TotalCases(N); 733740ae3bSHans Wennborg for (unsigned i = 0; i < N; ++i) { 743740ae3bSHans Wennborg const APInt &Hi = Clusters[i].High->getValue(); 753740ae3bSHans Wennborg const APInt &Lo = Clusters[i].Low->getValue(); 763740ae3bSHans Wennborg TotalCases[i] = (Hi - Lo).getLimitedValue() + 1; 773740ae3bSHans Wennborg if (i != 0) 783740ae3bSHans Wennborg TotalCases[i] += TotalCases[i - 1]; 793740ae3bSHans Wennborg } 803740ae3bSHans Wennborg 813740ae3bSHans Wennborg uint64_t Range = getJumpTableRange(Clusters,0, N - 1); 823740ae3bSHans Wennborg uint64_t NumCases = getJumpTableNumCases(TotalCases, 0, N - 1); 833740ae3bSHans Wennborg assert(NumCases < UINT64_MAX / 100); 843740ae3bSHans Wennborg assert(Range >= NumCases); 85aa10f050SEvandro Menezes 86aa10f050SEvandro Menezes // Cheap case: the whole range may be suitable for jump table. 870d987e41SHiroshi Yamauchi if (TLI->isSuitableForJumpTable(SI, NumCases, Range, PSI, BFI)) { 88829037a9SAmara Emerson CaseCluster JTCluster; 89829037a9SAmara Emerson if (buildJumpTable(Clusters, 0, N - 1, SI, DefaultMBB, JTCluster)) { 90829037a9SAmara Emerson Clusters[0] = JTCluster; 91829037a9SAmara Emerson Clusters.resize(1); 92829037a9SAmara Emerson return; 93829037a9SAmara Emerson } 94829037a9SAmara Emerson } 95829037a9SAmara Emerson 96829037a9SAmara Emerson // The algorithm below is not suitable for -O0. 97829037a9SAmara Emerson if (TM->getOptLevel() == CodeGenOpt::None) 98829037a9SAmara Emerson return; 99829037a9SAmara Emerson 100829037a9SAmara Emerson // Split Clusters into minimum number of dense partitions. The algorithm uses 101829037a9SAmara Emerson // the same idea as Kannan & Proebsting "Correction to 'Producing Good Code 102829037a9SAmara Emerson // for the Case Statement'" (1994), but builds the MinPartitions array in 103829037a9SAmara Emerson // reverse order to make it easier to reconstruct the partitions in ascending 104829037a9SAmara Emerson // order. In the choice between two optimal partitionings, it picks the one 105829037a9SAmara Emerson // which yields more jump tables. 106829037a9SAmara Emerson 107829037a9SAmara Emerson // MinPartitions[i] is the minimum nbr of partitions of Clusters[i..N-1]. 108829037a9SAmara Emerson SmallVector<unsigned, 8> MinPartitions(N); 109829037a9SAmara Emerson // LastElement[i] is the last element of the partition starting at i. 110829037a9SAmara Emerson SmallVector<unsigned, 8> LastElement(N); 1113740ae3bSHans Wennborg // PartitionsScore[i] is used to break ties when choosing between two 1123740ae3bSHans Wennborg // partitionings resulting in the same number of partitions. 1133740ae3bSHans Wennborg SmallVector<unsigned, 8> PartitionsScore(N); 114829037a9SAmara Emerson // For PartitionsScore, a small number of comparisons is considered as good as 115829037a9SAmara Emerson // a jump table and a single comparison is considered better than a jump 116829037a9SAmara Emerson // table. 117829037a9SAmara Emerson enum PartitionScores : unsigned { 118829037a9SAmara Emerson NoTable = 0, 119829037a9SAmara Emerson Table = 1, 120829037a9SAmara Emerson FewCases = 1, 121829037a9SAmara Emerson SingleCase = 2 122829037a9SAmara Emerson }; 123829037a9SAmara Emerson 124829037a9SAmara Emerson // Base case: There is only one way to partition Clusters[N-1]. 125829037a9SAmara Emerson MinPartitions[N - 1] = 1; 126829037a9SAmara Emerson LastElement[N - 1] = N - 1; 127829037a9SAmara Emerson PartitionsScore[N - 1] = PartitionScores::SingleCase; 128829037a9SAmara Emerson 129829037a9SAmara Emerson // Note: loop indexes are signed to avoid underflow. 130829037a9SAmara Emerson for (int64_t i = N - 2; i >= 0; i--) { 131829037a9SAmara Emerson // Find optimal partitioning of Clusters[i..N-1]. 132829037a9SAmara Emerson // Baseline: Put Clusters[i] into a partition on its own. 133829037a9SAmara Emerson MinPartitions[i] = MinPartitions[i + 1] + 1; 134829037a9SAmara Emerson LastElement[i] = i; 135829037a9SAmara Emerson PartitionsScore[i] = PartitionsScore[i + 1] + PartitionScores::SingleCase; 136829037a9SAmara Emerson 137829037a9SAmara Emerson // Search for a solution that results in fewer partitions. 138829037a9SAmara Emerson for (int64_t j = N - 1; j > i; j--) { 139829037a9SAmara Emerson // Try building a partition from Clusters[i..j]. 1403740ae3bSHans Wennborg Range = getJumpTableRange(Clusters, i, j); 1413740ae3bSHans Wennborg NumCases = getJumpTableNumCases(TotalCases, i, j); 1423740ae3bSHans Wennborg assert(NumCases < UINT64_MAX / 100); 1433740ae3bSHans Wennborg assert(Range >= NumCases); 1443740ae3bSHans Wennborg 1450d987e41SHiroshi Yamauchi if (TLI->isSuitableForJumpTable(SI, NumCases, Range, PSI, BFI)) { 146829037a9SAmara Emerson unsigned NumPartitions = 1 + (j == N - 1 ? 0 : MinPartitions[j + 1]); 147829037a9SAmara Emerson unsigned Score = j == N - 1 ? 0 : PartitionsScore[j + 1]; 148829037a9SAmara Emerson int64_t NumEntries = j - i + 1; 149829037a9SAmara Emerson 150829037a9SAmara Emerson if (NumEntries == 1) 151829037a9SAmara Emerson Score += PartitionScores::SingleCase; 152829037a9SAmara Emerson else if (NumEntries <= SmallNumberOfEntries) 153829037a9SAmara Emerson Score += PartitionScores::FewCases; 154829037a9SAmara Emerson else if (NumEntries >= MinJumpTableEntries) 155829037a9SAmara Emerson Score += PartitionScores::Table; 156829037a9SAmara Emerson 157829037a9SAmara Emerson // If this leads to fewer partitions, or to the same number of 158829037a9SAmara Emerson // partitions with better score, it is a better partitioning. 159829037a9SAmara Emerson if (NumPartitions < MinPartitions[i] || 160829037a9SAmara Emerson (NumPartitions == MinPartitions[i] && Score > PartitionsScore[i])) { 161829037a9SAmara Emerson MinPartitions[i] = NumPartitions; 162829037a9SAmara Emerson LastElement[i] = j; 163829037a9SAmara Emerson PartitionsScore[i] = Score; 164829037a9SAmara Emerson } 165829037a9SAmara Emerson } 166829037a9SAmara Emerson } 167829037a9SAmara Emerson } 168829037a9SAmara Emerson 169829037a9SAmara Emerson // Iterate over the partitions, replacing some with jump tables in-place. 170829037a9SAmara Emerson unsigned DstIndex = 0; 171829037a9SAmara Emerson for (unsigned First = 0, Last; First < N; First = Last + 1) { 172829037a9SAmara Emerson Last = LastElement[First]; 173829037a9SAmara Emerson assert(Last >= First); 174829037a9SAmara Emerson assert(DstIndex <= First); 175829037a9SAmara Emerson unsigned NumClusters = Last - First + 1; 176829037a9SAmara Emerson 177829037a9SAmara Emerson CaseCluster JTCluster; 178829037a9SAmara Emerson if (NumClusters >= MinJumpTableEntries && 179829037a9SAmara Emerson buildJumpTable(Clusters, First, Last, SI, DefaultMBB, JTCluster)) { 180829037a9SAmara Emerson Clusters[DstIndex++] = JTCluster; 181829037a9SAmara Emerson } else { 182829037a9SAmara Emerson for (unsigned I = First; I <= Last; ++I) 183829037a9SAmara Emerson std::memmove(&Clusters[DstIndex++], &Clusters[I], sizeof(Clusters[I])); 184829037a9SAmara Emerson } 185829037a9SAmara Emerson } 186829037a9SAmara Emerson Clusters.resize(DstIndex); 187829037a9SAmara Emerson } 188829037a9SAmara Emerson 189829037a9SAmara Emerson bool SwitchCG::SwitchLowering::buildJumpTable(const CaseClusterVector &Clusters, 190829037a9SAmara Emerson unsigned First, unsigned Last, 191829037a9SAmara Emerson const SwitchInst *SI, 192829037a9SAmara Emerson MachineBasicBlock *DefaultMBB, 193829037a9SAmara Emerson CaseCluster &JTCluster) { 194829037a9SAmara Emerson assert(First <= Last); 195829037a9SAmara Emerson 196829037a9SAmara Emerson auto Prob = BranchProbability::getZero(); 197829037a9SAmara Emerson unsigned NumCmps = 0; 198829037a9SAmara Emerson std::vector<MachineBasicBlock*> Table; 199829037a9SAmara Emerson DenseMap<MachineBasicBlock*, BranchProbability> JTProbs; 200829037a9SAmara Emerson 201829037a9SAmara Emerson // Initialize probabilities in JTProbs. 202829037a9SAmara Emerson for (unsigned I = First; I <= Last; ++I) 203829037a9SAmara Emerson JTProbs[Clusters[I].MBB] = BranchProbability::getZero(); 204829037a9SAmara Emerson 205829037a9SAmara Emerson for (unsigned I = First; I <= Last; ++I) { 206829037a9SAmara Emerson assert(Clusters[I].Kind == CC_Range); 207829037a9SAmara Emerson Prob += Clusters[I].Prob; 208829037a9SAmara Emerson const APInt &Low = Clusters[I].Low->getValue(); 209829037a9SAmara Emerson const APInt &High = Clusters[I].High->getValue(); 210829037a9SAmara Emerson NumCmps += (Low == High) ? 1 : 2; 211829037a9SAmara Emerson if (I != First) { 212829037a9SAmara Emerson // Fill the gap between this and the previous cluster. 213829037a9SAmara Emerson const APInt &PreviousHigh = Clusters[I - 1].High->getValue(); 214829037a9SAmara Emerson assert(PreviousHigh.slt(Low)); 215829037a9SAmara Emerson uint64_t Gap = (Low - PreviousHigh).getLimitedValue() - 1; 216829037a9SAmara Emerson for (uint64_t J = 0; J < Gap; J++) 217829037a9SAmara Emerson Table.push_back(DefaultMBB); 218829037a9SAmara Emerson } 219829037a9SAmara Emerson uint64_t ClusterSize = (High - Low).getLimitedValue() + 1; 220829037a9SAmara Emerson for (uint64_t J = 0; J < ClusterSize; ++J) 221829037a9SAmara Emerson Table.push_back(Clusters[I].MBB); 222829037a9SAmara Emerson JTProbs[Clusters[I].MBB] += Clusters[I].Prob; 223829037a9SAmara Emerson } 224829037a9SAmara Emerson 225829037a9SAmara Emerson unsigned NumDests = JTProbs.size(); 226829037a9SAmara Emerson if (TLI->isSuitableForBitTests(NumDests, NumCmps, 227829037a9SAmara Emerson Clusters[First].Low->getValue(), 228829037a9SAmara Emerson Clusters[Last].High->getValue(), *DL)) { 229829037a9SAmara Emerson // Clusters[First..Last] should be lowered as bit tests instead. 230829037a9SAmara Emerson return false; 231829037a9SAmara Emerson } 232829037a9SAmara Emerson 233829037a9SAmara Emerson // Create the MBB that will load from and jump through the table. 234829037a9SAmara Emerson // Note: We create it here, but it's not inserted into the function yet. 235829037a9SAmara Emerson MachineFunction *CurMF = FuncInfo.MF; 236829037a9SAmara Emerson MachineBasicBlock *JumpTableMBB = 237829037a9SAmara Emerson CurMF->CreateMachineBasicBlock(SI->getParent()); 238829037a9SAmara Emerson 239829037a9SAmara Emerson // Add successors. Note: use table order for determinism. 240829037a9SAmara Emerson SmallPtrSet<MachineBasicBlock *, 8> Done; 241829037a9SAmara Emerson for (MachineBasicBlock *Succ : Table) { 242829037a9SAmara Emerson if (Done.count(Succ)) 243829037a9SAmara Emerson continue; 244829037a9SAmara Emerson addSuccessorWithProb(JumpTableMBB, Succ, JTProbs[Succ]); 245829037a9SAmara Emerson Done.insert(Succ); 246829037a9SAmara Emerson } 247829037a9SAmara Emerson JumpTableMBB->normalizeSuccProbs(); 248829037a9SAmara Emerson 249829037a9SAmara Emerson unsigned JTI = CurMF->getOrCreateJumpTableInfo(TLI->getJumpTableEncoding()) 250829037a9SAmara Emerson ->createJumpTableIndex(Table); 251829037a9SAmara Emerson 252829037a9SAmara Emerson // Set up the jump table info. 253829037a9SAmara Emerson JumpTable JT(-1U, JTI, JumpTableMBB, nullptr); 254829037a9SAmara Emerson JumpTableHeader JTH(Clusters[First].Low->getValue(), 255829037a9SAmara Emerson Clusters[Last].High->getValue(), SI->getCondition(), 256829037a9SAmara Emerson nullptr, false); 257829037a9SAmara Emerson JTCases.emplace_back(std::move(JTH), std::move(JT)); 258829037a9SAmara Emerson 259829037a9SAmara Emerson JTCluster = CaseCluster::jumpTable(Clusters[First].Low, Clusters[Last].High, 260829037a9SAmara Emerson JTCases.size() - 1, Prob); 261829037a9SAmara Emerson return true; 262829037a9SAmara Emerson } 263829037a9SAmara Emerson 264829037a9SAmara Emerson void SwitchCG::SwitchLowering::findBitTestClusters(CaseClusterVector &Clusters, 265829037a9SAmara Emerson const SwitchInst *SI) { 266829037a9SAmara Emerson // Partition Clusters into as few subsets as possible, where each subset has a 267829037a9SAmara Emerson // range that fits in a machine word and has <= 3 unique destinations. 268829037a9SAmara Emerson 269829037a9SAmara Emerson #ifndef NDEBUG 270829037a9SAmara Emerson // Clusters must be sorted and contain Range or JumpTable clusters. 271829037a9SAmara Emerson assert(!Clusters.empty()); 272829037a9SAmara Emerson assert(Clusters[0].Kind == CC_Range || Clusters[0].Kind == CC_JumpTable); 273829037a9SAmara Emerson for (const CaseCluster &C : Clusters) 274829037a9SAmara Emerson assert(C.Kind == CC_Range || C.Kind == CC_JumpTable); 275829037a9SAmara Emerson for (unsigned i = 1; i < Clusters.size(); ++i) 276829037a9SAmara Emerson assert(Clusters[i-1].High->getValue().slt(Clusters[i].Low->getValue())); 277829037a9SAmara Emerson #endif 278829037a9SAmara Emerson 279829037a9SAmara Emerson // The algorithm below is not suitable for -O0. 280829037a9SAmara Emerson if (TM->getOptLevel() == CodeGenOpt::None) 281829037a9SAmara Emerson return; 282829037a9SAmara Emerson 283829037a9SAmara Emerson // If target does not have legal shift left, do not emit bit tests at all. 284829037a9SAmara Emerson EVT PTy = TLI->getPointerTy(*DL); 285829037a9SAmara Emerson if (!TLI->isOperationLegal(ISD::SHL, PTy)) 286829037a9SAmara Emerson return; 287829037a9SAmara Emerson 288829037a9SAmara Emerson int BitWidth = PTy.getSizeInBits(); 289829037a9SAmara Emerson const int64_t N = Clusters.size(); 290829037a9SAmara Emerson 291829037a9SAmara Emerson // MinPartitions[i] is the minimum nbr of partitions of Clusters[i..N-1]. 292829037a9SAmara Emerson SmallVector<unsigned, 8> MinPartitions(N); 293829037a9SAmara Emerson // LastElement[i] is the last element of the partition starting at i. 294829037a9SAmara Emerson SmallVector<unsigned, 8> LastElement(N); 295829037a9SAmara Emerson 296829037a9SAmara Emerson // FIXME: This might not be the best algorithm for finding bit test clusters. 297829037a9SAmara Emerson 298829037a9SAmara Emerson // Base case: There is only one way to partition Clusters[N-1]. 299829037a9SAmara Emerson MinPartitions[N - 1] = 1; 300829037a9SAmara Emerson LastElement[N - 1] = N - 1; 301829037a9SAmara Emerson 302829037a9SAmara Emerson // Note: loop indexes are signed to avoid underflow. 303829037a9SAmara Emerson for (int64_t i = N - 2; i >= 0; --i) { 304829037a9SAmara Emerson // Find optimal partitioning of Clusters[i..N-1]. 305829037a9SAmara Emerson // Baseline: Put Clusters[i] into a partition on its own. 306829037a9SAmara Emerson MinPartitions[i] = MinPartitions[i + 1] + 1; 307829037a9SAmara Emerson LastElement[i] = i; 308829037a9SAmara Emerson 309829037a9SAmara Emerson // Search for a solution that results in fewer partitions. 310829037a9SAmara Emerson // Note: the search is limited by BitWidth, reducing time complexity. 311829037a9SAmara Emerson for (int64_t j = std::min(N - 1, i + BitWidth - 1); j > i; --j) { 312829037a9SAmara Emerson // Try building a partition from Clusters[i..j]. 313829037a9SAmara Emerson 314829037a9SAmara Emerson // Check the range. 315829037a9SAmara Emerson if (!TLI->rangeFitsInWord(Clusters[i].Low->getValue(), 316829037a9SAmara Emerson Clusters[j].High->getValue(), *DL)) 317829037a9SAmara Emerson continue; 318829037a9SAmara Emerson 319829037a9SAmara Emerson // Check nbr of destinations and cluster types. 320829037a9SAmara Emerson // FIXME: This works, but doesn't seem very efficient. 321829037a9SAmara Emerson bool RangesOnly = true; 322829037a9SAmara Emerson BitVector Dests(FuncInfo.MF->getNumBlockIDs()); 323829037a9SAmara Emerson for (int64_t k = i; k <= j; k++) { 324829037a9SAmara Emerson if (Clusters[k].Kind != CC_Range) { 325829037a9SAmara Emerson RangesOnly = false; 326829037a9SAmara Emerson break; 327829037a9SAmara Emerson } 328829037a9SAmara Emerson Dests.set(Clusters[k].MBB->getNumber()); 329829037a9SAmara Emerson } 330829037a9SAmara Emerson if (!RangesOnly || Dests.count() > 3) 331829037a9SAmara Emerson break; 332829037a9SAmara Emerson 333829037a9SAmara Emerson // Check if it's a better partition. 334829037a9SAmara Emerson unsigned NumPartitions = 1 + (j == N - 1 ? 0 : MinPartitions[j + 1]); 335829037a9SAmara Emerson if (NumPartitions < MinPartitions[i]) { 336829037a9SAmara Emerson // Found a better partition. 337829037a9SAmara Emerson MinPartitions[i] = NumPartitions; 338829037a9SAmara Emerson LastElement[i] = j; 339829037a9SAmara Emerson } 340829037a9SAmara Emerson } 341829037a9SAmara Emerson } 342829037a9SAmara Emerson 343829037a9SAmara Emerson // Iterate over the partitions, replacing with bit-test clusters in-place. 344829037a9SAmara Emerson unsigned DstIndex = 0; 345829037a9SAmara Emerson for (unsigned First = 0, Last; First < N; First = Last + 1) { 346829037a9SAmara Emerson Last = LastElement[First]; 347829037a9SAmara Emerson assert(First <= Last); 348829037a9SAmara Emerson assert(DstIndex <= First); 349829037a9SAmara Emerson 350829037a9SAmara Emerson CaseCluster BitTestCluster; 351829037a9SAmara Emerson if (buildBitTests(Clusters, First, Last, SI, BitTestCluster)) { 352829037a9SAmara Emerson Clusters[DstIndex++] = BitTestCluster; 353829037a9SAmara Emerson } else { 354829037a9SAmara Emerson size_t NumClusters = Last - First + 1; 355829037a9SAmara Emerson std::memmove(&Clusters[DstIndex], &Clusters[First], 356829037a9SAmara Emerson sizeof(Clusters[0]) * NumClusters); 357829037a9SAmara Emerson DstIndex += NumClusters; 358829037a9SAmara Emerson } 359829037a9SAmara Emerson } 360829037a9SAmara Emerson Clusters.resize(DstIndex); 361829037a9SAmara Emerson } 362829037a9SAmara Emerson 363829037a9SAmara Emerson bool SwitchCG::SwitchLowering::buildBitTests(CaseClusterVector &Clusters, 364829037a9SAmara Emerson unsigned First, unsigned Last, 365829037a9SAmara Emerson const SwitchInst *SI, 366829037a9SAmara Emerson CaseCluster &BTCluster) { 367829037a9SAmara Emerson assert(First <= Last); 368829037a9SAmara Emerson if (First == Last) 369829037a9SAmara Emerson return false; 370829037a9SAmara Emerson 371829037a9SAmara Emerson BitVector Dests(FuncInfo.MF->getNumBlockIDs()); 372829037a9SAmara Emerson unsigned NumCmps = 0; 373829037a9SAmara Emerson for (int64_t I = First; I <= Last; ++I) { 374829037a9SAmara Emerson assert(Clusters[I].Kind == CC_Range); 375829037a9SAmara Emerson Dests.set(Clusters[I].MBB->getNumber()); 376829037a9SAmara Emerson NumCmps += (Clusters[I].Low == Clusters[I].High) ? 1 : 2; 377829037a9SAmara Emerson } 378829037a9SAmara Emerson unsigned NumDests = Dests.count(); 379829037a9SAmara Emerson 380829037a9SAmara Emerson APInt Low = Clusters[First].Low->getValue(); 381829037a9SAmara Emerson APInt High = Clusters[Last].High->getValue(); 382829037a9SAmara Emerson assert(Low.slt(High)); 383829037a9SAmara Emerson 384829037a9SAmara Emerson if (!TLI->isSuitableForBitTests(NumDests, NumCmps, Low, High, *DL)) 385829037a9SAmara Emerson return false; 386829037a9SAmara Emerson 387829037a9SAmara Emerson APInt LowBound; 388829037a9SAmara Emerson APInt CmpRange; 389829037a9SAmara Emerson 390829037a9SAmara Emerson const int BitWidth = TLI->getPointerTy(*DL).getSizeInBits(); 391829037a9SAmara Emerson assert(TLI->rangeFitsInWord(Low, High, *DL) && 392829037a9SAmara Emerson "Case range must fit in bit mask!"); 393829037a9SAmara Emerson 394829037a9SAmara Emerson // Check if the clusters cover a contiguous range such that no value in the 395829037a9SAmara Emerson // range will jump to the default statement. 396829037a9SAmara Emerson bool ContiguousRange = true; 397829037a9SAmara Emerson for (int64_t I = First + 1; I <= Last; ++I) { 398829037a9SAmara Emerson if (Clusters[I].Low->getValue() != Clusters[I - 1].High->getValue() + 1) { 399829037a9SAmara Emerson ContiguousRange = false; 400829037a9SAmara Emerson break; 401829037a9SAmara Emerson } 402829037a9SAmara Emerson } 403829037a9SAmara Emerson 404829037a9SAmara Emerson if (Low.isStrictlyPositive() && High.slt(BitWidth)) { 405829037a9SAmara Emerson // Optimize the case where all the case values fit in a word without having 406829037a9SAmara Emerson // to subtract minValue. In this case, we can optimize away the subtraction. 407829037a9SAmara Emerson LowBound = APInt::getNullValue(Low.getBitWidth()); 408829037a9SAmara Emerson CmpRange = High; 409829037a9SAmara Emerson ContiguousRange = false; 410829037a9SAmara Emerson } else { 411829037a9SAmara Emerson LowBound = Low; 412829037a9SAmara Emerson CmpRange = High - Low; 413829037a9SAmara Emerson } 414829037a9SAmara Emerson 415829037a9SAmara Emerson CaseBitsVector CBV; 416829037a9SAmara Emerson auto TotalProb = BranchProbability::getZero(); 417829037a9SAmara Emerson for (unsigned i = First; i <= Last; ++i) { 418829037a9SAmara Emerson // Find the CaseBits for this destination. 419829037a9SAmara Emerson unsigned j; 420829037a9SAmara Emerson for (j = 0; j < CBV.size(); ++j) 421829037a9SAmara Emerson if (CBV[j].BB == Clusters[i].MBB) 422829037a9SAmara Emerson break; 423829037a9SAmara Emerson if (j == CBV.size()) 424829037a9SAmara Emerson CBV.push_back( 425829037a9SAmara Emerson CaseBits(0, Clusters[i].MBB, 0, BranchProbability::getZero())); 426829037a9SAmara Emerson CaseBits *CB = &CBV[j]; 427829037a9SAmara Emerson 428829037a9SAmara Emerson // Update Mask, Bits and ExtraProb. 429829037a9SAmara Emerson uint64_t Lo = (Clusters[i].Low->getValue() - LowBound).getZExtValue(); 430829037a9SAmara Emerson uint64_t Hi = (Clusters[i].High->getValue() - LowBound).getZExtValue(); 431829037a9SAmara Emerson assert(Hi >= Lo && Hi < 64 && "Invalid bit case!"); 432829037a9SAmara Emerson CB->Mask |= (-1ULL >> (63 - (Hi - Lo))) << Lo; 433829037a9SAmara Emerson CB->Bits += Hi - Lo + 1; 434829037a9SAmara Emerson CB->ExtraProb += Clusters[i].Prob; 435829037a9SAmara Emerson TotalProb += Clusters[i].Prob; 436829037a9SAmara Emerson } 437829037a9SAmara Emerson 438829037a9SAmara Emerson BitTestInfo BTI; 439829037a9SAmara Emerson llvm::sort(CBV, [](const CaseBits &a, const CaseBits &b) { 440829037a9SAmara Emerson // Sort by probability first, number of bits second, bit mask third. 441829037a9SAmara Emerson if (a.ExtraProb != b.ExtraProb) 442829037a9SAmara Emerson return a.ExtraProb > b.ExtraProb; 443829037a9SAmara Emerson if (a.Bits != b.Bits) 444829037a9SAmara Emerson return a.Bits > b.Bits; 445829037a9SAmara Emerson return a.Mask < b.Mask; 446829037a9SAmara Emerson }); 447829037a9SAmara Emerson 448829037a9SAmara Emerson for (auto &CB : CBV) { 449829037a9SAmara Emerson MachineBasicBlock *BitTestBB = 450829037a9SAmara Emerson FuncInfo.MF->CreateMachineBasicBlock(SI->getParent()); 451829037a9SAmara Emerson BTI.push_back(BitTestCase(CB.Mask, BitTestBB, CB.BB, CB.ExtraProb)); 452829037a9SAmara Emerson } 453829037a9SAmara Emerson BitTestCases.emplace_back(std::move(LowBound), std::move(CmpRange), 454829037a9SAmara Emerson SI->getCondition(), -1U, MVT::Other, false, 455829037a9SAmara Emerson ContiguousRange, nullptr, nullptr, std::move(BTI), 456829037a9SAmara Emerson TotalProb); 457829037a9SAmara Emerson 458829037a9SAmara Emerson BTCluster = CaseCluster::bitTests(Clusters[First].Low, Clusters[Last].High, 459829037a9SAmara Emerson BitTestCases.size() - 1, TotalProb); 460829037a9SAmara Emerson return true; 461829037a9SAmara Emerson } 462829037a9SAmara Emerson 463829037a9SAmara Emerson void SwitchCG::sortAndRangeify(CaseClusterVector &Clusters) { 464829037a9SAmara Emerson #ifndef NDEBUG 465829037a9SAmara Emerson for (const CaseCluster &CC : Clusters) 466829037a9SAmara Emerson assert(CC.Low == CC.High && "Input clusters must be single-case"); 467829037a9SAmara Emerson #endif 468829037a9SAmara Emerson 469829037a9SAmara Emerson llvm::sort(Clusters, [](const CaseCluster &a, const CaseCluster &b) { 470829037a9SAmara Emerson return a.Low->getValue().slt(b.Low->getValue()); 471829037a9SAmara Emerson }); 472829037a9SAmara Emerson 473829037a9SAmara Emerson // Merge adjacent clusters with the same destination. 474829037a9SAmara Emerson const unsigned N = Clusters.size(); 475829037a9SAmara Emerson unsigned DstIndex = 0; 476829037a9SAmara Emerson for (unsigned SrcIndex = 0; SrcIndex < N; ++SrcIndex) { 477829037a9SAmara Emerson CaseCluster &CC = Clusters[SrcIndex]; 478829037a9SAmara Emerson const ConstantInt *CaseVal = CC.Low; 479829037a9SAmara Emerson MachineBasicBlock *Succ = CC.MBB; 480829037a9SAmara Emerson 481829037a9SAmara Emerson if (DstIndex != 0 && Clusters[DstIndex - 1].MBB == Succ && 482829037a9SAmara Emerson (CaseVal->getValue() - Clusters[DstIndex - 1].High->getValue()) == 1) { 483829037a9SAmara Emerson // If this case has the same successor and is a neighbour, merge it into 484829037a9SAmara Emerson // the previous cluster. 485829037a9SAmara Emerson Clusters[DstIndex - 1].High = CaseVal; 486829037a9SAmara Emerson Clusters[DstIndex - 1].Prob += CC.Prob; 487829037a9SAmara Emerson } else { 488829037a9SAmara Emerson std::memmove(&Clusters[DstIndex++], &Clusters[SrcIndex], 489829037a9SAmara Emerson sizeof(Clusters[SrcIndex])); 490829037a9SAmara Emerson } 491829037a9SAmara Emerson } 492829037a9SAmara Emerson Clusters.resize(DstIndex); 493829037a9SAmara Emerson } 494