1*2f09f445SMaksim Panchenko //===- bolt/Passes/ReorderAlgorithm.cpp - Basic block reordering ----------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8a34c753fSRafael Auler // 9*2f09f445SMaksim Panchenko // This file implements classes used by several basic block reordering 10*2f09f445SMaksim Panchenko // algorithms. 11a34c753fSRafael Auler // 12a34c753fSRafael Auler //===----------------------------------------------------------------------===// 13a34c753fSRafael Auler 14a34c753fSRafael Auler #include "bolt/Passes/ReorderAlgorithm.h" 15a34c753fSRafael Auler #include "bolt/Core/BinaryBasicBlock.h" 16a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h" 17a34c753fSRafael Auler #include "llvm/Support/CommandLine.h" 18a34c753fSRafael Auler #include <queue> 19a34c753fSRafael Auler #include <random> 20a34c753fSRafael Auler #include <stack> 21a34c753fSRafael Auler 22a34c753fSRafael Auler #undef DEBUG_TYPE 23a34c753fSRafael Auler #define DEBUG_TYPE "bolt" 24a34c753fSRafael Auler 25a34c753fSRafael Auler using namespace llvm; 26a34c753fSRafael Auler using namespace bolt; 27a34c753fSRafael Auler 28a34c753fSRafael Auler namespace opts { 29a34c753fSRafael Auler 30a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory; 31a34c753fSRafael Auler extern cl::opt<bool> NoThreads; 32a34c753fSRafael Auler 33a34c753fSRafael Auler static cl::opt<unsigned> ColdThreshold( 34a34c753fSRafael Auler "cold-threshold", 35a34c753fSRafael Auler cl::desc("tenths of percents of main entry frequency to use as a " 36a34c753fSRafael Auler "threshold when evaluating whether a basic block is cold " 37a34c753fSRafael Auler "(0 means it is only considered cold if the block has zero " 38a34c753fSRafael Auler "samples). Default: 0 "), 39a34c753fSRafael Auler cl::init(0), cl::ZeroOrMore, cl::Hidden, cl::cat(BoltOptCategory)); 40a34c753fSRafael Auler 41a34c753fSRafael Auler static cl::opt<bool> 42a34c753fSRafael Auler PrintClusters("print-clusters", 43a34c753fSRafael Auler cl::desc("print clusters"), 44a34c753fSRafael Auler cl::ZeroOrMore, 45a34c753fSRafael Auler cl::Hidden, 46a34c753fSRafael Auler cl::cat(BoltOptCategory)); 47a34c753fSRafael Auler 48a34c753fSRafael Auler cl::opt<uint32_t> 49a34c753fSRafael Auler RandomSeed("bolt-seed", 50a34c753fSRafael Auler cl::desc("seed for randomization"), 51a34c753fSRafael Auler cl::init(42), 52a34c753fSRafael Auler cl::ZeroOrMore, 53a34c753fSRafael Auler cl::Hidden, 54a34c753fSRafael Auler cl::cat(BoltOptCategory)); 55a34c753fSRafael Auler 56a34c753fSRafael Auler } // namespace opts 57a34c753fSRafael Auler 58a34c753fSRafael Auler namespace { 59a34c753fSRafael Auler 6040c2e0faSMaksim Panchenko template <class T> inline void hashCombine(size_t &Seed, const T &Val) { 61a34c753fSRafael Auler std::hash<T> Hasher; 62a34c753fSRafael Auler Seed ^= Hasher(Val) + 0x9e3779b9 + (Seed << 6) + (Seed >> 2); 63a34c753fSRafael Auler } 64a34c753fSRafael Auler 6540c2e0faSMaksim Panchenko template <typename A, typename B> struct HashPair { 66a34c753fSRafael Auler size_t operator()(const std::pair<A, B> &Val) const { 67a34c753fSRafael Auler std::hash<A> Hasher; 68a34c753fSRafael Auler size_t Seed = Hasher(Val.first); 69a34c753fSRafael Auler hashCombine(Seed, Val.second); 70a34c753fSRafael Auler return Seed; 71a34c753fSRafael Auler } 72a34c753fSRafael Auler }; 73a34c753fSRafael Auler 7440c2e0faSMaksim Panchenko } // namespace 75a34c753fSRafael Auler 76a34c753fSRafael Auler void ClusterAlgorithm::computeClusterAverageFrequency(const BinaryContext &BC) { 77a34c753fSRafael Auler // Create a separate MCCodeEmitter to allow lock-free execution 78a34c753fSRafael Auler BinaryContext::IndependentCodeEmitter Emitter; 79a34c753fSRafael Auler if (!opts::NoThreads) { 80a34c753fSRafael Auler Emitter = BC.createIndependentMCCodeEmitter(); 81a34c753fSRafael Auler } 82a34c753fSRafael Auler 83a34c753fSRafael Auler AvgFreq.resize(Clusters.size(), 0.0); 84a34c753fSRafael Auler for (uint32_t I = 0, E = Clusters.size(); I < E; ++I) { 85a34c753fSRafael Auler double Freq = 0.0; 86a34c753fSRafael Auler uint64_t ClusterSize = 0; 87a34c753fSRafael Auler for (BinaryBasicBlock *BB : Clusters[I]) { 88a34c753fSRafael Auler if (BB->getNumNonPseudos() > 0) { 89a34c753fSRafael Auler Freq += BB->getExecutionCount(); 90a34c753fSRafael Auler // Estimate the size of a block in bytes at run time 91a34c753fSRafael Auler // NOTE: This might be inaccurate 92a34c753fSRafael Auler ClusterSize += BB->estimateSize(Emitter.MCE.get()); 93a34c753fSRafael Auler } 94a34c753fSRafael Auler } 95a34c753fSRafael Auler AvgFreq[I] = ClusterSize == 0 ? 0 : Freq / ClusterSize; 96a34c753fSRafael Auler } 97a34c753fSRafael Auler } 98a34c753fSRafael Auler 99a34c753fSRafael Auler void ClusterAlgorithm::printClusters() const { 100a34c753fSRafael Auler for (uint32_t I = 0, E = Clusters.size(); I < E; ++I) { 101a34c753fSRafael Auler errs() << "Cluster number " << I; 102a34c753fSRafael Auler if (AvgFreq.size() == Clusters.size()) 103a34c753fSRafael Auler errs() << " (frequency: " << AvgFreq[I] << ")"; 104a34c753fSRafael Auler errs() << " : "; 105a34c753fSRafael Auler const char *Sep = ""; 106a34c753fSRafael Auler for (BinaryBasicBlock *BB : Clusters[I]) { 107a34c753fSRafael Auler errs() << Sep << BB->getName(); 108a34c753fSRafael Auler Sep = ", "; 109a34c753fSRafael Auler } 110a34c753fSRafael Auler errs() << "\n"; 111a34c753fSRafael Auler } 112a34c753fSRafael Auler } 113a34c753fSRafael Auler 114a34c753fSRafael Auler void ClusterAlgorithm::reset() { 115a34c753fSRafael Auler Clusters.clear(); 116a34c753fSRafael Auler ClusterEdges.clear(); 117a34c753fSRafael Auler AvgFreq.clear(); 118a34c753fSRafael Auler } 119a34c753fSRafael Auler 120a34c753fSRafael Auler void GreedyClusterAlgorithm::EdgeTy::print(raw_ostream &OS) const { 121a34c753fSRafael Auler OS << Src->getName() << " -> " << Dst->getName() << ", count: " << Count; 122a34c753fSRafael Auler } 123a34c753fSRafael Auler 124a34c753fSRafael Auler size_t GreedyClusterAlgorithm::EdgeHash::operator()(const EdgeTy &E) const { 125a34c753fSRafael Auler HashPair<const BinaryBasicBlock *, const BinaryBasicBlock *> Hasher; 126a34c753fSRafael Auler return Hasher(std::make_pair(E.Src, E.Dst)); 127a34c753fSRafael Auler } 128a34c753fSRafael Auler 12940c2e0faSMaksim Panchenko bool GreedyClusterAlgorithm::EdgeEqual::operator()(const EdgeTy &A, 13040c2e0faSMaksim Panchenko const EdgeTy &B) const { 131a34c753fSRafael Auler return A.Src == B.Src && A.Dst == B.Dst; 132a34c753fSRafael Auler } 133a34c753fSRafael Auler 134a34c753fSRafael Auler void GreedyClusterAlgorithm::clusterBasicBlocks(const BinaryFunction &BF, 135a34c753fSRafael Auler bool ComputeEdges) { 136a34c753fSRafael Auler reset(); 137a34c753fSRafael Auler 138a34c753fSRafael Auler // Greedy heuristic implementation for the TSP, applied to BB layout. Try to 139a34c753fSRafael Auler // maximize weight during a path traversing all BBs. In this way, we will 140a34c753fSRafael Auler // convert the hottest branches into fall-throughs. 141a34c753fSRafael Auler 142a34c753fSRafael Auler // This is the queue of edges from which we will pop edges and use them to 143a34c753fSRafael Auler // cluster basic blocks in a greedy fashion. 144a34c753fSRafael Auler std::vector<EdgeTy> Queue; 145a34c753fSRafael Auler 146a34c753fSRafael Auler // Initialize inter-cluster weights. 147a34c753fSRafael Auler if (ComputeEdges) 148a34c753fSRafael Auler ClusterEdges.resize(BF.layout_size()); 149a34c753fSRafael Auler 150a34c753fSRafael Auler // Initialize clusters and edge queue. 151a34c753fSRafael Auler for (BinaryBasicBlock *BB : BF.layout()) { 152a34c753fSRafael Auler // Create a cluster for this BB. 153a34c753fSRafael Auler uint32_t I = Clusters.size(); 154a34c753fSRafael Auler Clusters.emplace_back(); 155a34c753fSRafael Auler std::vector<BinaryBasicBlock *> &Cluster = Clusters.back(); 156a34c753fSRafael Auler Cluster.push_back(BB); 157a34c753fSRafael Auler BBToClusterMap[BB] = I; 158a34c753fSRafael Auler // Populate priority queue with edges. 159a34c753fSRafael Auler auto BI = BB->branch_info_begin(); 160a34c753fSRafael Auler for (BinaryBasicBlock *&I : BB->successors()) { 161a34c753fSRafael Auler assert(BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE && 162a34c753fSRafael Auler "attempted reordering blocks of function with no profile data"); 163a34c753fSRafael Auler Queue.emplace_back(EdgeTy(BB, I, BI->Count)); 164a34c753fSRafael Auler ++BI; 165a34c753fSRafael Auler } 166a34c753fSRafael Auler } 167a34c753fSRafael Auler // Sort and adjust the edge queue. 168a34c753fSRafael Auler initQueue(Queue, BF); 169a34c753fSRafael Auler 170a34c753fSRafael Auler // Grow clusters in a greedy fashion. 171a34c753fSRafael Auler while (!Queue.empty()) { 172a34c753fSRafael Auler EdgeTy E = Queue.back(); 173a34c753fSRafael Auler Queue.pop_back(); 174a34c753fSRafael Auler 175a34c753fSRafael Auler const BinaryBasicBlock *SrcBB = E.Src; 176a34c753fSRafael Auler const BinaryBasicBlock *DstBB = E.Dst; 177a34c753fSRafael Auler 178a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Popped edge "; E.print(dbgs()); dbgs() << "\n"); 179a34c753fSRafael Auler 180a34c753fSRafael Auler // Case 1: BBSrc and BBDst are the same. Ignore this edge 181a34c753fSRafael Auler if (SrcBB == DstBB || DstBB == *BF.layout_begin()) { 182a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tIgnored (same src, dst)\n"); 183a34c753fSRafael Auler continue; 184a34c753fSRafael Auler } 185a34c753fSRafael Auler 186a34c753fSRafael Auler int I = BBToClusterMap[SrcBB]; 187a34c753fSRafael Auler int J = BBToClusterMap[DstBB]; 188a34c753fSRafael Auler 189a34c753fSRafael Auler // Case 2: If they are already allocated at the same cluster, just increase 190a34c753fSRafael Auler // the weight of this cluster 191a34c753fSRafael Auler if (I == J) { 192a34c753fSRafael Auler if (ComputeEdges) 193a34c753fSRafael Auler ClusterEdges[I][I] += E.Count; 194a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tIgnored (src, dst belong to the same cluster)\n"); 195a34c753fSRafael Auler continue; 196a34c753fSRafael Auler } 197a34c753fSRafael Auler 198a34c753fSRafael Auler std::vector<BinaryBasicBlock *> &ClusterA = Clusters[I]; 199a34c753fSRafael Auler std::vector<BinaryBasicBlock *> &ClusterB = Clusters[J]; 200a34c753fSRafael Auler if (areClustersCompatible(ClusterA, ClusterB, E)) { 201a34c753fSRafael Auler // Case 3: SrcBB is at the end of a cluster and DstBB is at the start, 202a34c753fSRafael Auler // allowing us to merge two clusters. 203a34c753fSRafael Auler for (BinaryBasicBlock *BB : ClusterB) 204a34c753fSRafael Auler BBToClusterMap[BB] = I; 205a34c753fSRafael Auler ClusterA.insert(ClusterA.end(), ClusterB.begin(), ClusterB.end()); 206a34c753fSRafael Auler ClusterB.clear(); 207a34c753fSRafael Auler if (ComputeEdges) { 208a34c753fSRafael Auler // Increase the intra-cluster edge count of cluster A with the count of 209a34c753fSRafael Auler // this edge as well as with the total count of previously visited edges 210a34c753fSRafael Auler // from cluster B cluster A. 211a34c753fSRafael Auler ClusterEdges[I][I] += E.Count; 212a34c753fSRafael Auler ClusterEdges[I][I] += ClusterEdges[J][I]; 213a34c753fSRafael Auler // Iterate through all inter-cluster edges and transfer edges targeting 214a34c753fSRafael Auler // cluster B to cluster A. 215a34c753fSRafael Auler for (uint32_t K = 0, E = ClusterEdges.size(); K != E; ++K) 216a34c753fSRafael Auler ClusterEdges[K][I] += ClusterEdges[K][J]; 217a34c753fSRafael Auler } 218a34c753fSRafael Auler // Adjust the weights of the remaining edges and re-sort the queue. 219a34c753fSRafael Auler adjustQueue(Queue, BF); 220a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tMerged clusters of src, dst\n"); 221a34c753fSRafael Auler } else { 222a34c753fSRafael Auler // Case 4: Both SrcBB and DstBB are allocated in positions we cannot 223a34c753fSRafael Auler // merge them. Add the count of this edge to the inter-cluster edge count 224a34c753fSRafael Auler // between clusters A and B to help us decide ordering between these 225a34c753fSRafael Auler // clusters. 226a34c753fSRafael Auler if (ComputeEdges) 227a34c753fSRafael Auler ClusterEdges[I][J] += E.Count; 228a34c753fSRafael Auler LLVM_DEBUG( 229a34c753fSRafael Auler dbgs() << "\tIgnored (src, dst belong to incompatible clusters)\n"); 230a34c753fSRafael Auler } 231a34c753fSRafael Auler } 232a34c753fSRafael Auler } 233a34c753fSRafael Auler 234a34c753fSRafael Auler void GreedyClusterAlgorithm::reset() { 235a34c753fSRafael Auler ClusterAlgorithm::reset(); 236a34c753fSRafael Auler BBToClusterMap.clear(); 237a34c753fSRafael Auler } 238a34c753fSRafael Auler 23940c2e0faSMaksim Panchenko void PHGreedyClusterAlgorithm::initQueue(std::vector<EdgeTy> &Queue, 24040c2e0faSMaksim Panchenko const BinaryFunction &BF) { 241a34c753fSRafael Auler // Define a comparison function to establish SWO between edges. 242a34c753fSRafael Auler auto Comp = [&BF](const EdgeTy &A, const EdgeTy &B) { 243a34c753fSRafael Auler // With equal weights, prioritize branches with lower index 244a34c753fSRafael Auler // source/destination. This helps to keep original block order for blocks 245a34c753fSRafael Auler // when optimal order cannot be deducted from a profile. 246a34c753fSRafael Auler if (A.Count == B.Count) { 247a34c753fSRafael Auler const signed SrcOrder = BF.getOriginalLayoutRelativeOrder(A.Src, B.Src); 248a34c753fSRafael Auler return (SrcOrder != 0) 249a34c753fSRafael Auler ? SrcOrder > 0 250a34c753fSRafael Auler : BF.getOriginalLayoutRelativeOrder(A.Dst, B.Dst) > 0; 251a34c753fSRafael Auler } 252a34c753fSRafael Auler return A.Count < B.Count; 253a34c753fSRafael Auler }; 254a34c753fSRafael Auler 255a34c753fSRafael Auler // Sort edges in increasing profile count order. 256a34c753fSRafael Auler std::sort(Queue.begin(), Queue.end(), Comp); 257a34c753fSRafael Auler } 258a34c753fSRafael Auler 25940c2e0faSMaksim Panchenko void PHGreedyClusterAlgorithm::adjustQueue(std::vector<EdgeTy> &Queue, 26040c2e0faSMaksim Panchenko const BinaryFunction &BF) { 261a34c753fSRafael Auler // Nothing to do. 262a34c753fSRafael Auler return; 263a34c753fSRafael Auler } 264a34c753fSRafael Auler 26540c2e0faSMaksim Panchenko bool PHGreedyClusterAlgorithm::areClustersCompatible(const ClusterTy &Front, 26640c2e0faSMaksim Panchenko const ClusterTy &Back, 26740c2e0faSMaksim Panchenko const EdgeTy &E) const { 268a34c753fSRafael Auler return Front.back() == E.Src && Back.front() == E.Dst; 269a34c753fSRafael Auler } 270a34c753fSRafael Auler 271a34c753fSRafael Auler int64_t MinBranchGreedyClusterAlgorithm::calculateWeight( 272a34c753fSRafael Auler const EdgeTy &E, const BinaryFunction &BF) const { 273a34c753fSRafael Auler const BinaryBasicBlock *SrcBB = E.Src; 274a34c753fSRafael Auler const BinaryBasicBlock *DstBB = E.Dst; 275a34c753fSRafael Auler 276a34c753fSRafael Auler // Initial weight value. 277a34c753fSRafael Auler int64_t W = (int64_t)E.Count; 278a34c753fSRafael Auler 279a34c753fSRafael Auler // Adjust the weight by taking into account other edges with the same source. 280a34c753fSRafael Auler auto BI = SrcBB->branch_info_begin(); 281a34c753fSRafael Auler for (const BinaryBasicBlock *SuccBB : SrcBB->successors()) { 282a34c753fSRafael Auler assert(BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE && 283a34c753fSRafael Auler "attempted reordering blocks of function with no profile data"); 284a34c753fSRafael Auler assert(BI->Count <= std::numeric_limits<int64_t>::max() && 285a34c753fSRafael Auler "overflow detected"); 286a34c753fSRafael Auler // Ignore edges with same source and destination, edges that target the 287a34c753fSRafael Auler // entry block as well as the edge E itself. 288a34c753fSRafael Auler if (SuccBB != SrcBB && SuccBB != *BF.layout_begin() && SuccBB != DstBB) 289a34c753fSRafael Auler W -= (int64_t)BI->Count; 290a34c753fSRafael Auler ++BI; 291a34c753fSRafael Auler } 292a34c753fSRafael Auler 293a34c753fSRafael Auler // Adjust the weight by taking into account other edges with the same 294a34c753fSRafael Auler // destination. 295a34c753fSRafael Auler for (const BinaryBasicBlock *PredBB : DstBB->predecessors()) { 296a34c753fSRafael Auler // Ignore edges with same source and destination as well as the edge E 297a34c753fSRafael Auler // itself. 298a34c753fSRafael Auler if (PredBB == DstBB || PredBB == SrcBB) 299a34c753fSRafael Auler continue; 300a34c753fSRafael Auler auto BI = PredBB->branch_info_begin(); 301a34c753fSRafael Auler for (const BinaryBasicBlock *SuccBB : PredBB->successors()) { 302a34c753fSRafael Auler if (SuccBB == DstBB) 303a34c753fSRafael Auler break; 304a34c753fSRafael Auler ++BI; 305a34c753fSRafael Auler } 306a34c753fSRafael Auler assert(BI != PredBB->branch_info_end() && "invalid control flow graph"); 307a34c753fSRafael Auler assert(BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE && 308a34c753fSRafael Auler "attempted reordering blocks of function with no profile data"); 309a34c753fSRafael Auler assert(BI->Count <= std::numeric_limits<int64_t>::max() && 310a34c753fSRafael Auler "overflow detected"); 311a34c753fSRafael Auler W -= (int64_t)BI->Count; 312a34c753fSRafael Auler } 313a34c753fSRafael Auler 314a34c753fSRafael Auler return W; 315a34c753fSRafael Auler } 316a34c753fSRafael Auler 31740c2e0faSMaksim Panchenko void MinBranchGreedyClusterAlgorithm::initQueue(std::vector<EdgeTy> &Queue, 31840c2e0faSMaksim Panchenko const BinaryFunction &BF) { 319a34c753fSRafael Auler // Initialize edge weights. 320a34c753fSRafael Auler for (const EdgeTy &E : Queue) 321a34c753fSRafael Auler Weight.emplace(std::make_pair(E, calculateWeight(E, BF))); 322a34c753fSRafael Auler 323a34c753fSRafael Auler // Sort edges in increasing weight order. 324a34c753fSRafael Auler adjustQueue(Queue, BF); 325a34c753fSRafael Auler } 326a34c753fSRafael Auler 32740c2e0faSMaksim Panchenko void MinBranchGreedyClusterAlgorithm::adjustQueue(std::vector<EdgeTy> &Queue, 32840c2e0faSMaksim Panchenko const BinaryFunction &BF) { 329a34c753fSRafael Auler // Define a comparison function to establish SWO between edges. 330a34c753fSRafael Auler auto Comp = [&](const EdgeTy &A, const EdgeTy &B) { 331a34c753fSRafael Auler // With equal weights, prioritize branches with lower index 332a34c753fSRafael Auler // source/destination. This helps to keep original block order for blocks 333a34c753fSRafael Auler // when optimal order cannot be deduced from a profile. 334a34c753fSRafael Auler if (Weight[A] == Weight[B]) { 335a34c753fSRafael Auler const signed SrcOrder = BF.getOriginalLayoutRelativeOrder(A.Src, B.Src); 336a34c753fSRafael Auler return (SrcOrder != 0) 337a34c753fSRafael Auler ? SrcOrder > 0 338a34c753fSRafael Auler : BF.getOriginalLayoutRelativeOrder(A.Dst, B.Dst) > 0; 339a34c753fSRafael Auler } 340a34c753fSRafael Auler return Weight[A] < Weight[B]; 341a34c753fSRafael Auler }; 342a34c753fSRafael Auler 343a34c753fSRafael Auler // Iterate through all remaining edges to find edges that have their 344a34c753fSRafael Auler // source and destination in the same cluster. 345a34c753fSRafael Auler std::vector<EdgeTy> NewQueue; 346a34c753fSRafael Auler for (const EdgeTy &E : Queue) { 347a34c753fSRafael Auler const BinaryBasicBlock *SrcBB = E.Src; 348a34c753fSRafael Auler const BinaryBasicBlock *DstBB = E.Dst; 349a34c753fSRafael Auler 350a34c753fSRafael Auler // Case 1: SrcBB and DstBB are the same or DstBB is the entry block. Ignore 351a34c753fSRafael Auler // this edge. 352a34c753fSRafael Auler if (SrcBB == DstBB || DstBB == *BF.layout_begin()) { 353a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tAdjustment: Ignored edge "; E.print(dbgs()); 354a34c753fSRafael Auler dbgs() << " (same src, dst)\n"); 355a34c753fSRafael Auler continue; 356a34c753fSRafael Auler } 357a34c753fSRafael Auler 358a34c753fSRafael Auler int I = BBToClusterMap[SrcBB]; 359a34c753fSRafael Auler int J = BBToClusterMap[DstBB]; 360a34c753fSRafael Auler std::vector<BinaryBasicBlock *> &ClusterA = Clusters[I]; 361a34c753fSRafael Auler std::vector<BinaryBasicBlock *> &ClusterB = Clusters[J]; 362a34c753fSRafael Auler 363a34c753fSRafael Auler // Case 2: They are already allocated at the same cluster or incompatible 364a34c753fSRafael Auler // clusters. Adjust the weights of edges with the same source or 365a34c753fSRafael Auler // destination, so that this edge has no effect on them any more, and ignore 366a34c753fSRafael Auler // this edge. Also increase the intra- (or inter-) cluster edge count. 367a34c753fSRafael Auler if (I == J || !areClustersCompatible(ClusterA, ClusterB, E)) { 368a34c753fSRafael Auler if (!ClusterEdges.empty()) 369a34c753fSRafael Auler ClusterEdges[I][J] += E.Count; 370a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tAdjustment: Ignored edge "; E.print(dbgs()); 371a34c753fSRafael Auler dbgs() << " (src, dst belong to same cluster or incompatible " 372a34c753fSRafael Auler "clusters)\n"); 373a34c753fSRafael Auler for (const BinaryBasicBlock *SuccBB : SrcBB->successors()) { 374a34c753fSRafael Auler if (SuccBB == DstBB) 375a34c753fSRafael Auler continue; 376a34c753fSRafael Auler auto WI = Weight.find(EdgeTy(SrcBB, SuccBB, 0)); 377a34c753fSRafael Auler assert(WI != Weight.end() && "CFG edge not found in Weight map"); 378a34c753fSRafael Auler WI->second += (int64_t)E.Count; 379a34c753fSRafael Auler } 380a34c753fSRafael Auler for (const BinaryBasicBlock *PredBB : DstBB->predecessors()) { 381a34c753fSRafael Auler if (PredBB == SrcBB) 382a34c753fSRafael Auler continue; 383a34c753fSRafael Auler auto WI = Weight.find(EdgeTy(PredBB, DstBB, 0)); 384a34c753fSRafael Auler assert(WI != Weight.end() && "CFG edge not found in Weight map"); 385a34c753fSRafael Auler WI->second += (int64_t)E.Count; 386a34c753fSRafael Auler } 387a34c753fSRafael Auler continue; 388a34c753fSRafael Auler } 389a34c753fSRafael Auler 390a34c753fSRafael Auler // Case 3: None of the previous cases is true, so just keep this edge in 391a34c753fSRafael Auler // the queue. 392a34c753fSRafael Auler NewQueue.emplace_back(E); 393a34c753fSRafael Auler } 394a34c753fSRafael Auler 395a34c753fSRafael Auler // Sort remaining edges in increasing weight order. 396a34c753fSRafael Auler Queue.swap(NewQueue); 397a34c753fSRafael Auler std::sort(Queue.begin(), Queue.end(), Comp); 398a34c753fSRafael Auler } 399a34c753fSRafael Auler 400a34c753fSRafael Auler bool MinBranchGreedyClusterAlgorithm::areClustersCompatible( 401a34c753fSRafael Auler const ClusterTy &Front, const ClusterTy &Back, const EdgeTy &E) const { 402a34c753fSRafael Auler return Front.back() == E.Src && Back.front() == E.Dst; 403a34c753fSRafael Auler } 404a34c753fSRafael Auler 405a34c753fSRafael Auler void MinBranchGreedyClusterAlgorithm::reset() { 406a34c753fSRafael Auler GreedyClusterAlgorithm::reset(); 407a34c753fSRafael Auler Weight.clear(); 408a34c753fSRafael Auler } 409a34c753fSRafael Auler 41040c2e0faSMaksim Panchenko void TSPReorderAlgorithm::reorderBasicBlocks(const BinaryFunction &BF, 41140c2e0faSMaksim Panchenko BasicBlockOrder &Order) const { 412a34c753fSRafael Auler std::vector<std::vector<uint64_t>> Weight; 413a34c753fSRafael Auler std::vector<BinaryBasicBlock *> IndexToBB; 414a34c753fSRafael Auler 415a34c753fSRafael Auler const size_t N = BF.layout_size(); 416a34c753fSRafael Auler assert(N <= std::numeric_limits<uint64_t>::digits && 417a34c753fSRafael Auler "cannot use TSP solution for sizes larger than bits in uint64_t"); 418a34c753fSRafael Auler 419a34c753fSRafael Auler // Populating weight map and index map 420a34c753fSRafael Auler for (BinaryBasicBlock *BB : BF.layout()) { 421a34c753fSRafael Auler BB->setLayoutIndex(IndexToBB.size()); 422a34c753fSRafael Auler IndexToBB.push_back(BB); 423a34c753fSRafael Auler } 424a34c753fSRafael Auler Weight.resize(N); 425a34c753fSRafael Auler for (BinaryBasicBlock *BB : BF.layout()) { 426a34c753fSRafael Auler auto BI = BB->branch_info_begin(); 427a34c753fSRafael Auler Weight[BB->getLayoutIndex()].resize(N); 428a34c753fSRafael Auler for (BinaryBasicBlock *SuccBB : BB->successors()) { 429a34c753fSRafael Auler if (BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE) 430a34c753fSRafael Auler Weight[BB->getLayoutIndex()][SuccBB->getLayoutIndex()] = BI->Count; 431a34c753fSRafael Auler ++BI; 432a34c753fSRafael Auler } 433a34c753fSRafael Auler } 434a34c753fSRafael Auler 435a34c753fSRafael Auler std::vector<std::vector<int64_t>> DP; 436a34c753fSRafael Auler DP.resize(1 << N); 437a34c753fSRafael Auler for (std::vector<int64_t> &Elmt : DP) { 438a34c753fSRafael Auler Elmt.resize(N, -1); 439a34c753fSRafael Auler } 440a34c753fSRafael Auler // Start with the entry basic block being allocated with cost zero 441a34c753fSRafael Auler DP[1][0] = 0; 442a34c753fSRafael Auler // Walk through TSP solutions using a bitmask to represent state (current set 443a34c753fSRafael Auler // of BBs in the layout) 444a34c753fSRafael Auler uint64_t BestSet = 1; 445a34c753fSRafael Auler uint64_t BestLast = 0; 446a34c753fSRafael Auler int64_t BestWeight = 0; 447a34c753fSRafael Auler for (uint64_t Set = 1; Set < (1ULL << N); ++Set) { 448a34c753fSRafael Auler // Traverse each possibility of Last BB visited in this layout 449a34c753fSRafael Auler for (uint64_t Last = 0; Last < N; ++Last) { 450a34c753fSRafael Auler // Case 1: There is no possible layout with this BB as Last 451a34c753fSRafael Auler if (DP[Set][Last] == -1) 452a34c753fSRafael Auler continue; 453a34c753fSRafael Auler 454a34c753fSRafael Auler // Case 2: There is a layout with this Set and this Last, and we try 455a34c753fSRafael Auler // to expand this set with New 456a34c753fSRafael Auler for (uint64_t New = 1; New < N; ++New) { 457a34c753fSRafael Auler // Case 2a: BB "New" is already in this Set 458a34c753fSRafael Auler if ((Set & (1ULL << New)) != 0) 459a34c753fSRafael Auler continue; 460a34c753fSRafael Auler 461a34c753fSRafael Auler // Case 2b: BB "New" is not in this set and we add it to this Set and 462a34c753fSRafael Auler // record total weight of this layout with "New" as the last BB. 463a34c753fSRafael Auler uint64_t NewSet = (Set | (1ULL << New)); 464a34c753fSRafael Auler if (DP[NewSet][New] == -1) 465a34c753fSRafael Auler DP[NewSet][New] = DP[Set][Last] + (int64_t)Weight[Last][New]; 466a34c753fSRafael Auler DP[NewSet][New] = std::max(DP[NewSet][New], 467a34c753fSRafael Auler DP[Set][Last] + (int64_t)Weight[Last][New]); 468a34c753fSRafael Auler 469a34c753fSRafael Auler if (DP[NewSet][New] > BestWeight) { 470a34c753fSRafael Auler BestWeight = DP[NewSet][New]; 471a34c753fSRafael Auler BestSet = NewSet; 472a34c753fSRafael Auler BestLast = New; 473a34c753fSRafael Auler } 474a34c753fSRafael Auler } 475a34c753fSRafael Auler } 476a34c753fSRafael Auler } 477a34c753fSRafael Auler 478a34c753fSRafael Auler // Define final function layout based on layout that maximizes weight 479a34c753fSRafael Auler uint64_t Last = BestLast; 480a34c753fSRafael Auler uint64_t Set = BestSet; 481a34c753fSRafael Auler std::vector<bool> Visited; 482a34c753fSRafael Auler Visited.resize(N); 483a34c753fSRafael Auler Visited[Last] = true; 484a34c753fSRafael Auler Order.push_back(IndexToBB[Last]); 485a34c753fSRafael Auler Set = Set & ~(1ULL << Last); 486a34c753fSRafael Auler while (Set != 0) { 487a34c753fSRafael Auler int64_t Best = -1; 488a34c753fSRafael Auler uint64_t NewLast; 489a34c753fSRafael Auler for (uint64_t I = 0; I < N; ++I) { 490a34c753fSRafael Auler if (DP[Set][I] == -1) 491a34c753fSRafael Auler continue; 492a34c753fSRafael Auler int64_t AdjWeight = Weight[I][Last] > 0 ? Weight[I][Last] : 0; 493a34c753fSRafael Auler if (DP[Set][I] + AdjWeight > Best) { 494a34c753fSRafael Auler NewLast = I; 495a34c753fSRafael Auler Best = DP[Set][I] + AdjWeight; 496a34c753fSRafael Auler } 497a34c753fSRafael Auler } 498a34c753fSRafael Auler Last = NewLast; 499a34c753fSRafael Auler Visited[Last] = true; 500a34c753fSRafael Auler Order.push_back(IndexToBB[Last]); 501a34c753fSRafael Auler Set = Set & ~(1ULL << Last); 502a34c753fSRafael Auler } 503a34c753fSRafael Auler std::reverse(Order.begin(), Order.end()); 504a34c753fSRafael Auler 505a34c753fSRafael Auler // Finalize layout with BBs that weren't assigned to the layout using the 506a34c753fSRafael Auler // input layout. 507a34c753fSRafael Auler for (BinaryBasicBlock *BB : BF.layout()) { 508a34c753fSRafael Auler if (Visited[BB->getLayoutIndex()] == false) 509a34c753fSRafael Auler Order.push_back(BB); 510a34c753fSRafael Auler } 511a34c753fSRafael Auler } 512a34c753fSRafael Auler 513a34c753fSRafael Auler void OptimizeReorderAlgorithm::reorderBasicBlocks( 514a34c753fSRafael Auler const BinaryFunction &BF, BasicBlockOrder &Order) const { 515a34c753fSRafael Auler if (BF.layout_empty()) 516a34c753fSRafael Auler return; 517a34c753fSRafael Auler 518a34c753fSRafael Auler // Cluster basic blocks. 519a34c753fSRafael Auler CAlgo->clusterBasicBlocks(BF); 520a34c753fSRafael Auler 521a34c753fSRafael Auler if (opts::PrintClusters) 522a34c753fSRafael Auler CAlgo->printClusters(); 523a34c753fSRafael Auler 524a34c753fSRafael Auler // Arrange basic blocks according to clusters. 525a34c753fSRafael Auler for (ClusterAlgorithm::ClusterTy &Cluster : CAlgo->Clusters) 526a34c753fSRafael Auler Order.insert(Order.end(), Cluster.begin(), Cluster.end()); 527a34c753fSRafael Auler } 528a34c753fSRafael Auler 529a34c753fSRafael Auler void OptimizeBranchReorderAlgorithm::reorderBasicBlocks( 530a34c753fSRafael Auler const BinaryFunction &BF, BasicBlockOrder &Order) const { 531a34c753fSRafael Auler if (BF.layout_empty()) 532a34c753fSRafael Auler return; 533a34c753fSRafael Auler 534a34c753fSRafael Auler // Cluster basic blocks. 535a34c753fSRafael Auler CAlgo->clusterBasicBlocks(BF, /* ComputeEdges = */ true); 536a34c753fSRafael Auler std::vector<ClusterAlgorithm::ClusterTy> &Clusters = CAlgo->Clusters; 537a34c753fSRafael Auler std::vector<std::unordered_map<uint32_t, uint64_t>> &ClusterEdges = 538a34c753fSRafael Auler CAlgo->ClusterEdges; 539a34c753fSRafael Auler 540a34c753fSRafael Auler // Compute clusters' average frequencies. 541a34c753fSRafael Auler CAlgo->computeClusterAverageFrequency(BF.getBinaryContext()); 542a34c753fSRafael Auler std::vector<double> &AvgFreq = CAlgo->AvgFreq; 543a34c753fSRafael Auler 544a34c753fSRafael Auler if (opts::PrintClusters) 545a34c753fSRafael Auler CAlgo->printClusters(); 546a34c753fSRafael Auler 547a34c753fSRafael Auler // Cluster layout order 548a34c753fSRafael Auler std::vector<uint32_t> ClusterOrder; 549a34c753fSRafael Auler 550a34c753fSRafael Auler // Do a topological sort for clusters, prioritizing frequently-executed BBs 551a34c753fSRafael Auler // during the traversal. 552a34c753fSRafael Auler std::stack<uint32_t> Stack; 553a34c753fSRafael Auler std::vector<uint32_t> Status; 554a34c753fSRafael Auler std::vector<uint32_t> Parent; 555a34c753fSRafael Auler Status.resize(Clusters.size(), 0); 556a34c753fSRafael Auler Parent.resize(Clusters.size(), 0); 557a34c753fSRafael Auler constexpr uint32_t STACKED = 1; 558a34c753fSRafael Auler constexpr uint32_t VISITED = 2; 559a34c753fSRafael Auler Status[0] = STACKED; 560a34c753fSRafael Auler Stack.push(0); 561a34c753fSRafael Auler while (!Stack.empty()) { 562a34c753fSRafael Auler uint32_t I = Stack.top(); 563a34c753fSRafael Auler if (!(Status[I] & VISITED)) { 564a34c753fSRafael Auler Status[I] |= VISITED; 565a34c753fSRafael Auler // Order successors by weight 566a34c753fSRafael Auler auto ClusterComp = [&ClusterEdges, I](uint32_t A, uint32_t B) { 567a34c753fSRafael Auler return ClusterEdges[I][A] > ClusterEdges[I][B]; 568a34c753fSRafael Auler }; 569a34c753fSRafael Auler std::priority_queue<uint32_t, std::vector<uint32_t>, 57040c2e0faSMaksim Panchenko decltype(ClusterComp)> 57140c2e0faSMaksim Panchenko SuccQueue(ClusterComp); 572a34c753fSRafael Auler for (std::pair<const uint32_t, uint64_t> &Target : ClusterEdges[I]) { 573a34c753fSRafael Auler if (Target.second > 0 && !(Status[Target.first] & STACKED) && 574a34c753fSRafael Auler !Clusters[Target.first].empty()) { 575a34c753fSRafael Auler Parent[Target.first] = I; 576a34c753fSRafael Auler Status[Target.first] = STACKED; 577a34c753fSRafael Auler SuccQueue.push(Target.first); 578a34c753fSRafael Auler } 579a34c753fSRafael Auler } 580a34c753fSRafael Auler while (!SuccQueue.empty()) { 581a34c753fSRafael Auler Stack.push(SuccQueue.top()); 582a34c753fSRafael Auler SuccQueue.pop(); 583a34c753fSRafael Auler } 584a34c753fSRafael Auler continue; 585a34c753fSRafael Auler } 586a34c753fSRafael Auler // Already visited this node 587a34c753fSRafael Auler Stack.pop(); 588a34c753fSRafael Auler ClusterOrder.push_back(I); 589a34c753fSRafael Auler } 590a34c753fSRafael Auler std::reverse(ClusterOrder.begin(), ClusterOrder.end()); 591a34c753fSRafael Auler // Put unreachable clusters at the end 592a34c753fSRafael Auler for (uint32_t I = 0, E = Clusters.size(); I < E; ++I) 593a34c753fSRafael Auler if (!(Status[I] & VISITED) && !Clusters[I].empty()) 594a34c753fSRafael Auler ClusterOrder.push_back(I); 595a34c753fSRafael Auler 596a34c753fSRafael Auler // Sort nodes with equal precedence 597a34c753fSRafael Auler auto Beg = ClusterOrder.begin(); 598a34c753fSRafael Auler // Don't reorder the first cluster, which contains the function entry point 599a34c753fSRafael Auler ++Beg; 600a34c753fSRafael Auler std::stable_sort(Beg, ClusterOrder.end(), 601a34c753fSRafael Auler [&AvgFreq, &Parent](uint32_t A, uint32_t B) { 602a34c753fSRafael Auler uint32_t P = Parent[A]; 603a34c753fSRafael Auler while (Parent[P] != 0) { 604a34c753fSRafael Auler if (Parent[P] == B) 605a34c753fSRafael Auler return false; 606a34c753fSRafael Auler P = Parent[P]; 607a34c753fSRafael Auler } 608a34c753fSRafael Auler P = Parent[B]; 609a34c753fSRafael Auler while (Parent[P] != 0) { 610a34c753fSRafael Auler if (Parent[P] == A) 611a34c753fSRafael Auler return true; 612a34c753fSRafael Auler P = Parent[P]; 613a34c753fSRafael Auler } 614a34c753fSRafael Auler return AvgFreq[A] > AvgFreq[B]; 615a34c753fSRafael Auler }); 616a34c753fSRafael Auler 617a34c753fSRafael Auler if (opts::PrintClusters) { 618a34c753fSRafael Auler errs() << "New cluster order: "; 619a34c753fSRafael Auler const char *Sep = ""; 620a34c753fSRafael Auler for (uint32_t O : ClusterOrder) { 621a34c753fSRafael Auler errs() << Sep << O; 622a34c753fSRafael Auler Sep = ", "; 623a34c753fSRafael Auler } 624a34c753fSRafael Auler errs() << '\n'; 625a34c753fSRafael Auler } 626a34c753fSRafael Auler 627a34c753fSRafael Auler // Arrange basic blocks according to cluster order. 628a34c753fSRafael Auler for (uint32_t ClusterIndex : ClusterOrder) { 629a34c753fSRafael Auler ClusterAlgorithm::ClusterTy &Cluster = Clusters[ClusterIndex]; 630a34c753fSRafael Auler Order.insert(Order.end(), Cluster.begin(), Cluster.end()); 631a34c753fSRafael Auler } 632a34c753fSRafael Auler } 633a34c753fSRafael Auler 634a34c753fSRafael Auler void OptimizeCacheReorderAlgorithm::reorderBasicBlocks( 635a34c753fSRafael Auler const BinaryFunction &BF, BasicBlockOrder &Order) const { 636a34c753fSRafael Auler if (BF.layout_empty()) 637a34c753fSRafael Auler return; 638a34c753fSRafael Auler 639a34c753fSRafael Auler const uint64_t ColdThreshold = 640a34c753fSRafael Auler opts::ColdThreshold * (*BF.layout_begin())->getExecutionCount() / 1000; 641a34c753fSRafael Auler 642a34c753fSRafael Auler // Cluster basic blocks. 643a34c753fSRafael Auler CAlgo->clusterBasicBlocks(BF); 644a34c753fSRafael Auler std::vector<ClusterAlgorithm::ClusterTy> &Clusters = CAlgo->Clusters; 645a34c753fSRafael Auler 646a34c753fSRafael Auler // Compute clusters' average frequencies. 647a34c753fSRafael Auler CAlgo->computeClusterAverageFrequency(BF.getBinaryContext()); 648a34c753fSRafael Auler std::vector<double> &AvgFreq = CAlgo->AvgFreq; 649a34c753fSRafael Auler 650a34c753fSRafael Auler if (opts::PrintClusters) 651a34c753fSRafael Auler CAlgo->printClusters(); 652a34c753fSRafael Auler 653a34c753fSRafael Auler // Cluster layout order 654a34c753fSRafael Auler std::vector<uint32_t> ClusterOrder; 655a34c753fSRafael Auler 656a34c753fSRafael Auler // Order clusters based on average instruction execution frequency 657a34c753fSRafael Auler for (uint32_t I = 0, E = Clusters.size(); I < E; ++I) 658a34c753fSRafael Auler if (!Clusters[I].empty()) 659a34c753fSRafael Auler ClusterOrder.push_back(I); 660a34c753fSRafael Auler // Don't reorder the first cluster, which contains the function entry point 66140c2e0faSMaksim Panchenko std::stable_sort( 66240c2e0faSMaksim Panchenko std::next(ClusterOrder.begin()), ClusterOrder.end(), 66340c2e0faSMaksim Panchenko [&AvgFreq](uint32_t A, uint32_t B) { return AvgFreq[A] > AvgFreq[B]; }); 664a34c753fSRafael Auler 665a34c753fSRafael Auler if (opts::PrintClusters) { 666a34c753fSRafael Auler errs() << "New cluster order: "; 667a34c753fSRafael Auler const char *Sep = ""; 668a34c753fSRafael Auler for (uint32_t O : ClusterOrder) { 669a34c753fSRafael Auler errs() << Sep << O; 670a34c753fSRafael Auler Sep = ", "; 671a34c753fSRafael Auler } 672a34c753fSRafael Auler errs() << '\n'; 673a34c753fSRafael Auler } 674a34c753fSRafael Auler 675a34c753fSRafael Auler // Arrange basic blocks according to cluster order. 676a34c753fSRafael Auler for (uint32_t ClusterIndex : ClusterOrder) { 677a34c753fSRafael Auler ClusterAlgorithm::ClusterTy &Cluster = Clusters[ClusterIndex]; 678a34c753fSRafael Auler Order.insert(Order.end(), Cluster.begin(), Cluster.end()); 679a34c753fSRafael Auler // Force zero execution count on clusters that do not meet the cut off 680a34c753fSRafael Auler // specified by --cold-threshold. 681a34c753fSRafael Auler if (AvgFreq[ClusterIndex] < static_cast<double>(ColdThreshold)) { 682a34c753fSRafael Auler for (BinaryBasicBlock *BBPtr : Cluster) { 683a34c753fSRafael Auler BBPtr->setExecutionCount(0); 684a34c753fSRafael Auler } 685a34c753fSRafael Auler } 686a34c753fSRafael Auler } 687a34c753fSRafael Auler } 688a34c753fSRafael Auler 68940c2e0faSMaksim Panchenko void ReverseReorderAlgorithm::reorderBasicBlocks(const BinaryFunction &BF, 69040c2e0faSMaksim Panchenko BasicBlockOrder &Order) const { 691a34c753fSRafael Auler if (BF.layout_empty()) 692a34c753fSRafael Auler return; 693a34c753fSRafael Auler 694a34c753fSRafael Auler BinaryBasicBlock *FirstBB = *BF.layout_begin(); 695a34c753fSRafael Auler Order.push_back(FirstBB); 696a34c753fSRafael Auler for (auto RLI = BF.layout_rbegin(); *RLI != FirstBB; ++RLI) 697a34c753fSRafael Auler Order.push_back(*RLI); 698a34c753fSRafael Auler } 699a34c753fSRafael Auler 700a34c753fSRafael Auler void RandomClusterReorderAlgorithm::reorderBasicBlocks( 701a34c753fSRafael Auler const BinaryFunction &BF, BasicBlockOrder &Order) const { 702a34c753fSRafael Auler if (BF.layout_empty()) 703a34c753fSRafael Auler return; 704a34c753fSRafael Auler 705a34c753fSRafael Auler // Cluster basic blocks. 706a34c753fSRafael Auler CAlgo->clusterBasicBlocks(BF); 707a34c753fSRafael Auler std::vector<ClusterAlgorithm::ClusterTy> &Clusters = CAlgo->Clusters; 708a34c753fSRafael Auler 709a34c753fSRafael Auler if (opts::PrintClusters) 710a34c753fSRafael Auler CAlgo->printClusters(); 711a34c753fSRafael Auler 712a34c753fSRafael Auler // Cluster layout order 713a34c753fSRafael Auler std::vector<uint32_t> ClusterOrder; 714a34c753fSRafael Auler 715a34c753fSRafael Auler // Order clusters based on average instruction execution frequency 716a34c753fSRafael Auler for (uint32_t I = 0, E = Clusters.size(); I < E; ++I) 717a34c753fSRafael Auler if (!Clusters[I].empty()) 718a34c753fSRafael Auler ClusterOrder.push_back(I); 719a34c753fSRafael Auler 720a34c753fSRafael Auler std::shuffle(std::next(ClusterOrder.begin()), ClusterOrder.end(), 721a34c753fSRafael Auler std::default_random_engine(opts::RandomSeed.getValue())); 722a34c753fSRafael Auler 723a34c753fSRafael Auler if (opts::PrintClusters) { 724a34c753fSRafael Auler errs() << "New cluster order: "; 725a34c753fSRafael Auler const char *Sep = ""; 726a34c753fSRafael Auler for (uint32_t O : ClusterOrder) { 727a34c753fSRafael Auler errs() << Sep << O; 728a34c753fSRafael Auler Sep = ", "; 729a34c753fSRafael Auler } 730a34c753fSRafael Auler errs() << '\n'; 731a34c753fSRafael Auler } 732a34c753fSRafael Auler 733a34c753fSRafael Auler // Arrange basic blocks according to cluster order. 734a34c753fSRafael Auler for (uint32_t ClusterIndex : ClusterOrder) { 735a34c753fSRafael Auler ClusterAlgorithm::ClusterTy &Cluster = Clusters[ClusterIndex]; 736a34c753fSRafael Auler Order.insert(Order.end(), Cluster.begin(), Cluster.end()); 737a34c753fSRafael Auler } 738a34c753fSRafael Auler } 739