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