1*2f09f445SMaksim Panchenko //===- bolt/Passes/ReorderFunctions.cpp - Function reordering pass --------===//
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 ReorderFunctions class.
10*2f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "bolt/Passes/ReorderFunctions.h"
14a34c753fSRafael Auler #include "bolt/Passes/HFSort.h"
15a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
16a34c753fSRafael Auler #include <fstream>
17a34c753fSRafael Auler 
18a34c753fSRafael Auler #define DEBUG_TYPE "hfsort"
19a34c753fSRafael Auler 
20a34c753fSRafael Auler using namespace llvm;
21a34c753fSRafael Auler 
22a34c753fSRafael Auler namespace opts {
23a34c753fSRafael Auler 
24a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory;
25a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity;
26a34c753fSRafael Auler extern cl::opt<uint32_t> RandomSeed;
27a34c753fSRafael Auler 
28a34c753fSRafael Auler extern size_t padFunction(const bolt::BinaryFunction &Function);
29a34c753fSRafael Auler 
30a34c753fSRafael Auler cl::opt<bolt::ReorderFunctions::ReorderType>
31a34c753fSRafael Auler ReorderFunctions("reorder-functions",
32a34c753fSRafael Auler   cl::desc("reorder and cluster functions (works only with relocations)"),
33a34c753fSRafael Auler   cl::init(bolt::ReorderFunctions::RT_NONE),
34a34c753fSRafael Auler   cl::values(clEnumValN(bolt::ReorderFunctions::RT_NONE,
35a34c753fSRafael Auler       "none",
36a34c753fSRafael Auler       "do not reorder functions"),
37a34c753fSRafael Auler     clEnumValN(bolt::ReorderFunctions::RT_EXEC_COUNT,
38a34c753fSRafael Auler       "exec-count",
39a34c753fSRafael Auler       "order by execution count"),
40a34c753fSRafael Auler     clEnumValN(bolt::ReorderFunctions::RT_HFSORT,
41a34c753fSRafael Auler       "hfsort",
42a34c753fSRafael Auler       "use hfsort algorithm"),
43a34c753fSRafael Auler     clEnumValN(bolt::ReorderFunctions::RT_HFSORT_PLUS,
44a34c753fSRafael Auler       "hfsort+",
45a34c753fSRafael Auler       "use hfsort+ algorithm"),
46a34c753fSRafael Auler     clEnumValN(bolt::ReorderFunctions::RT_PETTIS_HANSEN,
47a34c753fSRafael Auler       "pettis-hansen",
48a34c753fSRafael Auler       "use Pettis-Hansen algorithm"),
49a34c753fSRafael Auler     clEnumValN(bolt::ReorderFunctions::RT_RANDOM,
50a34c753fSRafael Auler       "random",
51a34c753fSRafael Auler       "reorder functions randomly"),
52a34c753fSRafael Auler     clEnumValN(bolt::ReorderFunctions::RT_USER,
53a34c753fSRafael Auler       "user",
54a34c753fSRafael Auler       "use function order specified by -function-order")),
55a34c753fSRafael Auler   cl::ZeroOrMore,
56a34c753fSRafael Auler   cl::cat(BoltOptCategory));
57a34c753fSRafael Auler 
58a34c753fSRafael Auler static cl::opt<bool>
59a34c753fSRafael Auler ReorderFunctionsUseHotSize("reorder-functions-use-hot-size",
60a34c753fSRafael Auler   cl::desc("use a function's hot size when doing clustering"),
61a34c753fSRafael Auler   cl::init(true),
62a34c753fSRafael Auler   cl::ZeroOrMore,
63a34c753fSRafael Auler   cl::cat(BoltOptCategory));
64a34c753fSRafael Auler 
65a34c753fSRafael Auler static cl::opt<std::string>
66a34c753fSRafael Auler FunctionOrderFile("function-order",
67a34c753fSRafael Auler   cl::desc("file containing an ordered list of functions to use for function "
68a34c753fSRafael Auler            "reordering"),
69a34c753fSRafael Auler   cl::cat(BoltOptCategory));
70a34c753fSRafael Auler 
71a34c753fSRafael Auler static cl::opt<std::string>
72a34c753fSRafael Auler GenerateFunctionOrderFile("generate-function-order",
73a34c753fSRafael Auler   cl::desc("file to dump the ordered list of functions to use for function "
74a34c753fSRafael Auler            "reordering"),
75a34c753fSRafael Auler   cl::cat(BoltOptCategory));
76a34c753fSRafael Auler 
77a34c753fSRafael Auler static cl::opt<std::string>
78a34c753fSRafael Auler LinkSectionsFile("generate-link-sections",
79a34c753fSRafael Auler   cl::desc("generate a list of function sections in a format suitable for "
80a34c753fSRafael Auler            "inclusion in a linker script"),
81a34c753fSRafael Auler   cl::cat(BoltOptCategory));
82a34c753fSRafael Auler 
83a34c753fSRafael Auler static cl::opt<bool>
84a34c753fSRafael Auler UseEdgeCounts("use-edge-counts",
85a34c753fSRafael Auler   cl::desc("use edge count data when doing clustering"),
86a34c753fSRafael Auler   cl::init(true),
87a34c753fSRafael Auler   cl::ZeroOrMore,
88a34c753fSRafael Auler   cl::cat(BoltOptCategory));
89a34c753fSRafael Auler 
90a34c753fSRafael Auler static cl::opt<bool>
91a34c753fSRafael Auler CgFromPerfData("cg-from-perf-data",
92a34c753fSRafael Auler   cl::desc("use perf data directly when constructing the call graph"
93a34c753fSRafael Auler            " for stale functions"),
94a34c753fSRafael Auler   cl::init(true),
95a34c753fSRafael Auler   cl::ZeroOrMore,
96a34c753fSRafael Auler   cl::cat(BoltOptCategory));
97a34c753fSRafael Auler 
98a34c753fSRafael Auler static cl::opt<bool>
99a34c753fSRafael Auler CgIgnoreRecursiveCalls("cg-ignore-recursive-calls",
100a34c753fSRafael Auler   cl::desc("ignore recursive calls when constructing the call graph"),
101a34c753fSRafael Auler   cl::init(true),
102a34c753fSRafael Auler   cl::ZeroOrMore,
103a34c753fSRafael Auler   cl::cat(BoltOptCategory));
104a34c753fSRafael Auler 
105a34c753fSRafael Auler static cl::opt<bool>
106a34c753fSRafael Auler CgUseSplitHotSize("cg-use-split-hot-size",
107a34c753fSRafael Auler   cl::desc("use hot/cold data on basic blocks to determine hot sizes for "
108a34c753fSRafael Auler            "call graph functions"),
109a34c753fSRafael Auler   cl::init(false),
110a34c753fSRafael Auler   cl::ZeroOrMore,
111a34c753fSRafael Auler   cl::cat(BoltOptCategory));
112a34c753fSRafael Auler 
113a34c753fSRafael Auler } // namespace opts
114a34c753fSRafael Auler 
115a34c753fSRafael Auler namespace llvm {
116a34c753fSRafael Auler namespace bolt {
117a34c753fSRafael Auler 
118a34c753fSRafael Auler using NodeId = CallGraph::NodeId;
119a34c753fSRafael Auler using Arc = CallGraph::Arc;
120a34c753fSRafael Auler using Node = CallGraph::Node;
121a34c753fSRafael Auler 
122a34c753fSRafael Auler void ReorderFunctions::reorder(std::vector<Cluster> &&Clusters,
123a34c753fSRafael Auler                                std::map<uint64_t, BinaryFunction> &BFs) {
124a34c753fSRafael Auler   std::vector<uint64_t> FuncAddr(Cg.numNodes()); // Just for computing stats
125a34c753fSRafael Auler   uint64_t TotalSize = 0;
126a34c753fSRafael Auler   uint32_t Index = 0;
127a34c753fSRafael Auler 
128a34c753fSRafael Auler   // Set order of hot functions based on clusters.
129a34c753fSRafael Auler   for (const Cluster &Cluster : Clusters) {
130a34c753fSRafael Auler     for (const NodeId FuncId : Cluster.targets()) {
131a34c753fSRafael Auler       Cg.nodeIdToFunc(FuncId)->setIndex(Index++);
132a34c753fSRafael Auler       FuncAddr[FuncId] = TotalSize;
133a34c753fSRafael Auler       TotalSize += Cg.size(FuncId);
134a34c753fSRafael Auler     }
135a34c753fSRafael Auler   }
136a34c753fSRafael Auler 
137a34c753fSRafael Auler   if (opts::ReorderFunctions == RT_NONE)
138a34c753fSRafael Auler     return;
139a34c753fSRafael Auler 
140a34c753fSRafael Auler   if (opts::Verbosity == 0) {
141a34c753fSRafael Auler #ifndef NDEBUG
142a34c753fSRafael Auler     if (!DebugFlag || !isCurrentDebugType("hfsort"))
143a34c753fSRafael Auler       return;
144a34c753fSRafael Auler #else
145a34c753fSRafael Auler     return;
146a34c753fSRafael Auler #endif
147a34c753fSRafael Auler   }
148a34c753fSRafael Auler 
149a34c753fSRafael Auler   bool PrintDetailed = opts::Verbosity > 1;
150a34c753fSRafael Auler #ifndef NDEBUG
151a34c753fSRafael Auler   PrintDetailed |=
152a34c753fSRafael Auler     (DebugFlag && isCurrentDebugType("hfsort") && opts::Verbosity > 0);
153a34c753fSRafael Auler #endif
154a34c753fSRafael Auler   TotalSize   = 0;
155a34c753fSRafael Auler   uint64_t CurPage     = 0;
156a34c753fSRafael Auler   uint64_t Hotfuncs    = 0;
157a34c753fSRafael Auler   double TotalDistance = 0;
158a34c753fSRafael Auler   double TotalCalls    = 0;
159a34c753fSRafael Auler   double TotalCalls64B = 0;
160a34c753fSRafael Auler   double TotalCalls4KB = 0;
161a34c753fSRafael Auler   double TotalCalls2MB = 0;
162a34c753fSRafael Auler   if (PrintDetailed) {
163a34c753fSRafael Auler     outs() << "BOLT-INFO: Function reordering page layout\n"
164a34c753fSRafael Auler            << "BOLT-INFO: ============== page 0 ==============\n";
165a34c753fSRafael Auler   }
166a34c753fSRafael Auler   for (Cluster &Cluster : Clusters) {
167a34c753fSRafael Auler     if (PrintDetailed) {
16840c2e0faSMaksim Panchenko       outs() << format(
16940c2e0faSMaksim Panchenko           "BOLT-INFO: -------- density = %.3lf (%u / %u) --------\n",
170a34c753fSRafael Auler           Cluster.density(), Cluster.samples(), Cluster.size());
171a34c753fSRafael Auler     }
172a34c753fSRafael Auler 
173a34c753fSRafael Auler     for (NodeId FuncId : Cluster.targets()) {
174a34c753fSRafael Auler       if (Cg.samples(FuncId) > 0) {
175a34c753fSRafael Auler         Hotfuncs++;
176a34c753fSRafael Auler 
177a34c753fSRafael Auler         if (PrintDetailed) {
17840c2e0faSMaksim Panchenko           outs() << "BOLT-INFO: hot func " << *Cg.nodeIdToFunc(FuncId) << " ("
17940c2e0faSMaksim Panchenko                  << Cg.size(FuncId) << ")\n";
180a34c753fSRafael Auler         }
181a34c753fSRafael Auler 
182a34c753fSRafael Auler         uint64_t Dist = 0;
183a34c753fSRafael Auler         uint64_t Calls = 0;
184a34c753fSRafael Auler         for (NodeId Dst : Cg.successors(FuncId)) {
185a34c753fSRafael Auler           if (FuncId == Dst) // ignore recursive calls in stats
186a34c753fSRafael Auler             continue;
187a34c753fSRafael Auler           const Arc &Arc = *Cg.findArc(FuncId, Dst);
188a34c753fSRafael Auler           const auto D = std::abs(FuncAddr[Arc.dst()] -
189a34c753fSRafael Auler                                   (FuncAddr[FuncId] + Arc.avgCallOffset()));
190a34c753fSRafael Auler           const double W = Arc.weight();
191a34c753fSRafael Auler           if (D < 64 && PrintDetailed && opts::Verbosity > 2) {
192a34c753fSRafael Auler             outs() << "BOLT-INFO: short (" << D << "B) call:\n"
193a34c753fSRafael Auler                    << "BOLT-INFO:   Src: " << *Cg.nodeIdToFunc(FuncId) << "\n"
194a34c753fSRafael Auler                    << "BOLT-INFO:   Dst: " << *Cg.nodeIdToFunc(Dst) << "\n"
195a34c753fSRafael Auler                    << "BOLT-INFO:   Weight = " << W << "\n"
196a34c753fSRafael Auler                    << "BOLT-INFO:   AvgOffset = " << Arc.avgCallOffset() << "\n";
197a34c753fSRafael Auler           }
198a34c753fSRafael Auler           Calls += W;
199a34c753fSRafael Auler           if (D < 64)        TotalCalls64B += W;
200a34c753fSRafael Auler           if (D < 4096)      TotalCalls4KB += W;
201a34c753fSRafael Auler           if (D < (2 << 20)) TotalCalls2MB += W;
202a34c753fSRafael Auler           Dist += Arc.weight() * D;
203a34c753fSRafael Auler           if (PrintDetailed) {
204a34c753fSRafael Auler             outs() << format("BOLT-INFO: arc: %u [@%lu+%.1lf] -> %u [@%lu]: "
205a34c753fSRafael Auler                              "weight = %.0lf, callDist = %f\n",
206a34c753fSRafael Auler                              Arc.src(),
207a34c753fSRafael Auler                              FuncAddr[Arc.src()],
208a34c753fSRafael Auler                              Arc.avgCallOffset(),
209a34c753fSRafael Auler                              Arc.dst(),
210a34c753fSRafael Auler                              FuncAddr[Arc.dst()],
211a34c753fSRafael Auler                              Arc.weight(), D);
212a34c753fSRafael Auler           }
213a34c753fSRafael Auler         }
214a34c753fSRafael Auler         TotalCalls += Calls;
215a34c753fSRafael Auler         TotalDistance += Dist;
216a34c753fSRafael Auler         TotalSize += Cg.size(FuncId);
217a34c753fSRafael Auler 
218a34c753fSRafael Auler         if (PrintDetailed) {
219a34c753fSRafael Auler           outs() << format("BOLT-INFO: start = %6u : avgCallDist = %lu : ",
22040c2e0faSMaksim Panchenko                            TotalSize, Calls ? Dist / Calls : 0)
221a34c753fSRafael Auler                  << Cg.nodeIdToFunc(FuncId)->getPrintName() << '\n';
222a34c753fSRafael Auler           const uint64_t NewPage = TotalSize / HugePageSize;
223a34c753fSRafael Auler           if (NewPage != CurPage) {
224a34c753fSRafael Auler             CurPage = NewPage;
22540c2e0faSMaksim Panchenko             outs() << format(
22640c2e0faSMaksim Panchenko                 "BOLT-INFO: ============== page %u ==============\n", CurPage);
227a34c753fSRafael Auler           }
228a34c753fSRafael Auler         }
229a34c753fSRafael Auler       }
230a34c753fSRafael Auler     }
231a34c753fSRafael Auler   }
232a34c753fSRafael Auler   outs() << "BOLT-INFO: Function reordering stats\n"
233a34c753fSRafael Auler          << format("BOLT-INFO:  Number of hot functions: %u\n"
234a34c753fSRafael Auler                    "BOLT-INFO:  Number of clusters: %lu\n",
235a34c753fSRafael Auler                    Hotfuncs, Clusters.size())
236a34c753fSRafael Auler          << format("BOLT-INFO:  Final average call distance = %.1lf "
237a34c753fSRafael Auler                    "(%.0lf / %.0lf)\n",
23840c2e0faSMaksim Panchenko                    TotalCalls ? TotalDistance / TotalCalls : 0, TotalDistance,
23940c2e0faSMaksim Panchenko                    TotalCalls)
240a34c753fSRafael Auler          << format("BOLT-INFO:  Total Calls = %.0lf\n", TotalCalls);
241a34c753fSRafael Auler   if (TotalCalls) {
242a34c753fSRafael Auler     outs() << format("BOLT-INFO:  Total Calls within 64B = %.0lf (%.2lf%%)\n",
243a34c753fSRafael Auler                      TotalCalls64B, 100 * TotalCalls64B / TotalCalls)
244a34c753fSRafael Auler            << format("BOLT-INFO:  Total Calls within 4KB = %.0lf (%.2lf%%)\n",
245a34c753fSRafael Auler                      TotalCalls4KB, 100 * TotalCalls4KB / TotalCalls)
246a34c753fSRafael Auler            << format("BOLT-INFO:  Total Calls within 2MB = %.0lf (%.2lf%%)\n",
247a34c753fSRafael Auler                      TotalCalls2MB, 100 * TotalCalls2MB / TotalCalls);
248a34c753fSRafael Auler   }
249a34c753fSRafael Auler }
250a34c753fSRafael Auler 
251a34c753fSRafael Auler namespace {
252a34c753fSRafael Auler 
253a34c753fSRafael Auler std::vector<std::string> readFunctionOrderFile() {
254a34c753fSRafael Auler   std::vector<std::string> FunctionNames;
255a34c753fSRafael Auler   std::ifstream FuncsFile(opts::FunctionOrderFile, std::ios::in);
256a34c753fSRafael Auler   if (!FuncsFile) {
257a34c753fSRafael Auler     errs() << "Ordered functions file \"" << opts::FunctionOrderFile
258a34c753fSRafael Auler            << "\" can't be opened.\n";
259a34c753fSRafael Auler     exit(1);
260a34c753fSRafael Auler   }
261a34c753fSRafael Auler   std::string FuncName;
262a34c753fSRafael Auler   while (std::getline(FuncsFile, FuncName)) {
263a34c753fSRafael Auler     FunctionNames.push_back(FuncName);
264a34c753fSRafael Auler   }
265a34c753fSRafael Auler   return FunctionNames;
266a34c753fSRafael Auler }
267a34c753fSRafael Auler 
268a34c753fSRafael Auler }
269a34c753fSRafael Auler 
270a34c753fSRafael Auler void ReorderFunctions::runOnFunctions(BinaryContext &BC) {
271a34c753fSRafael Auler   auto &BFs = BC.getBinaryFunctions();
272a34c753fSRafael Auler   if (opts::ReorderFunctions != RT_NONE &&
273a34c753fSRafael Auler       opts::ReorderFunctions != RT_EXEC_COUNT &&
274a34c753fSRafael Auler       opts::ReorderFunctions != RT_USER) {
275a34c753fSRafael Auler     Cg = buildCallGraph(BC,
276a34c753fSRafael Auler                         [](const BinaryFunction &BF) {
277a34c753fSRafael Auler                           if (!BF.hasProfile())
278a34c753fSRafael Auler                             return true;
279a34c753fSRafael Auler                           if (BF.getState() != BinaryFunction::State::CFG)
280a34c753fSRafael Auler                             return true;
281a34c753fSRafael Auler                           return false;
282a34c753fSRafael Auler                         },
283a34c753fSRafael Auler                         opts::CgFromPerfData,
284a34c753fSRafael Auler                         false, // IncludeColdCalls
285a34c753fSRafael Auler                         opts::ReorderFunctionsUseHotSize,
286a34c753fSRafael Auler                         opts::CgUseSplitHotSize,
287a34c753fSRafael Auler                         opts::UseEdgeCounts,
288a34c753fSRafael Auler                         opts::CgIgnoreRecursiveCalls);
289a34c753fSRafael Auler     Cg.normalizeArcWeights();
290a34c753fSRafael Auler   }
291a34c753fSRafael Auler 
292a34c753fSRafael Auler   std::vector<Cluster> Clusters;
293a34c753fSRafael Auler 
294a34c753fSRafael Auler   switch (opts::ReorderFunctions) {
295a34c753fSRafael Auler   case RT_NONE:
296a34c753fSRafael Auler     break;
297a34c753fSRafael Auler   case RT_EXEC_COUNT:
298a34c753fSRafael Auler     {
299a34c753fSRafael Auler       std::vector<BinaryFunction *> SortedFunctions(BFs.size());
300a34c753fSRafael Auler       uint32_t Index = 0;
301a34c753fSRafael Auler       std::transform(BFs.begin(),
302a34c753fSRafael Auler                      BFs.end(),
303a34c753fSRafael Auler                      SortedFunctions.begin(),
304a34c753fSRafael Auler                      [](std::pair<const uint64_t, BinaryFunction> &BFI) {
305a34c753fSRafael Auler                        return &BFI.second;
306a34c753fSRafael Auler                      });
307a34c753fSRafael Auler       std::stable_sort(SortedFunctions.begin(), SortedFunctions.end(),
308a34c753fSRafael Auler                        [&](const BinaryFunction *A, const BinaryFunction *B) {
309a34c753fSRafael Auler                          if (A->isIgnored())
310a34c753fSRafael Auler                            return false;
311a34c753fSRafael Auler                          const size_t PadA = opts::padFunction(*A);
312a34c753fSRafael Auler                          const size_t PadB = opts::padFunction(*B);
313a34c753fSRafael Auler                          if (!PadA || !PadB) {
314a34c753fSRafael Auler                            if (PadA)
315a34c753fSRafael Auler                              return true;
316a34c753fSRafael Auler                            if (PadB)
317a34c753fSRafael Auler                              return false;
318a34c753fSRafael Auler                          }
319a34c753fSRafael Auler                          return !A->hasProfile() &&
320a34c753fSRafael Auler                            (B->hasProfile() ||
321a34c753fSRafael Auler                             (A->getExecutionCount() > B->getExecutionCount()));
322a34c753fSRafael Auler                        });
323a34c753fSRafael Auler       for (BinaryFunction *BF : SortedFunctions) {
324a34c753fSRafael Auler         if (BF->hasProfile())
325a34c753fSRafael Auler           BF->setIndex(Index++);
326a34c753fSRafael Auler       }
327a34c753fSRafael Auler     }
328a34c753fSRafael Auler     break;
329a34c753fSRafael Auler   case RT_HFSORT:
330a34c753fSRafael Auler     Clusters = clusterize(Cg);
331a34c753fSRafael Auler     break;
332a34c753fSRafael Auler   case RT_HFSORT_PLUS:
333a34c753fSRafael Auler     Clusters = hfsortPlus(Cg);
334a34c753fSRafael Auler     break;
335a34c753fSRafael Auler   case RT_PETTIS_HANSEN:
336a34c753fSRafael Auler     Clusters = pettisAndHansen(Cg);
337a34c753fSRafael Auler     break;
338a34c753fSRafael Auler   case RT_RANDOM:
339a34c753fSRafael Auler     std::srand(opts::RandomSeed);
340a34c753fSRafael Auler     Clusters = randomClusters(Cg);
341a34c753fSRafael Auler     break;
342a34c753fSRafael Auler   case RT_USER:
343a34c753fSRafael Auler     {
344a34c753fSRafael Auler       uint32_t Index = 0;
345a34c753fSRafael Auler       for (const std::string &Function : readFunctionOrderFile()) {
346a34c753fSRafael Auler         std::vector<uint64_t> FuncAddrs;
347a34c753fSRafael Auler 
348a34c753fSRafael Auler         BinaryData *BD = BC.getBinaryDataByName(Function);
349a34c753fSRafael Auler         if (!BD) {
350a34c753fSRafael Auler           uint32_t LocalID = 1;
351a34c753fSRafael Auler           while(1) {
352a34c753fSRafael Auler             // If we can't find the main symbol name, look for alternates.
353a34c753fSRafael Auler             const std::string FuncName =
354a34c753fSRafael Auler                 Function + "/" + std::to_string(LocalID);
355a34c753fSRafael Auler             BD = BC.getBinaryDataByName(FuncName);
356a34c753fSRafael Auler             if (BD)
357a34c753fSRafael Auler               FuncAddrs.push_back(BD->getAddress());
358a34c753fSRafael Auler             else
359a34c753fSRafael Auler               break;
360a34c753fSRafael Auler             LocalID++;
361a34c753fSRafael Auler           }
362a34c753fSRafael Auler         } else {
363a34c753fSRafael Auler           FuncAddrs.push_back(BD->getAddress());
364a34c753fSRafael Auler         }
365a34c753fSRafael Auler 
366a34c753fSRafael Auler         if (FuncAddrs.empty()) {
367a34c753fSRafael Auler           errs() << "BOLT-WARNING: Reorder functions: can't find function for "
368a34c753fSRafael Auler                  << Function << ".\n";
369a34c753fSRafael Auler           continue;
370a34c753fSRafael Auler         }
371a34c753fSRafael Auler 
372a34c753fSRafael Auler         for (const uint64_t FuncAddr : FuncAddrs) {
373a34c753fSRafael Auler           const BinaryData *FuncBD = BC.getBinaryDataAtAddress(FuncAddr);
374a34c753fSRafael Auler           assert(FuncBD);
375a34c753fSRafael Auler 
376a34c753fSRafael Auler           BinaryFunction *BF = BC.getFunctionForSymbol(FuncBD->getSymbol());
377a34c753fSRafael Auler           if (!BF) {
378a34c753fSRafael Auler             errs() << "BOLT-WARNING: Reorder functions: can't find function for "
379a34c753fSRafael Auler                    << Function << ".\n";
380a34c753fSRafael Auler             break;
381a34c753fSRafael Auler           }
382a34c753fSRafael Auler           if (!BF->hasValidIndex()) {
383a34c753fSRafael Auler             BF->setIndex(Index++);
384a34c753fSRafael Auler           } else if (opts::Verbosity > 0) {
385a34c753fSRafael Auler             errs() << "BOLT-WARNING: Duplicate reorder entry for " << Function
386a34c753fSRafael Auler                    << ".\n";
387a34c753fSRafael Auler           }
388a34c753fSRafael Auler         }
389a34c753fSRafael Auler       }
390a34c753fSRafael Auler     }
391a34c753fSRafael Auler     break;
392a34c753fSRafael Auler   }
393a34c753fSRafael Auler 
394a34c753fSRafael Auler   reorder(std::move(Clusters), BFs);
395a34c753fSRafael Auler 
396a34c753fSRafael Auler   std::unique_ptr<std::ofstream> FuncsFile;
397a34c753fSRafael Auler   if (!opts::GenerateFunctionOrderFile.empty()) {
39840c2e0faSMaksim Panchenko     FuncsFile = std::make_unique<std::ofstream>(opts::GenerateFunctionOrderFile,
399a34c753fSRafael Auler                                                 std::ios::out);
400a34c753fSRafael Auler     if (!FuncsFile) {
401a34c753fSRafael Auler       errs() << "BOLT-ERROR: ordered functions file "
402a34c753fSRafael Auler              << opts::GenerateFunctionOrderFile << " cannot be opened\n";
403a34c753fSRafael Auler       exit(1);
404a34c753fSRafael Auler     }
405a34c753fSRafael Auler   }
406a34c753fSRafael Auler 
407a34c753fSRafael Auler   std::unique_ptr<std::ofstream> LinkSectionsFile;
408a34c753fSRafael Auler   if (!opts::LinkSectionsFile.empty()) {
409a34c753fSRafael Auler     LinkSectionsFile =
41040c2e0faSMaksim Panchenko         std::make_unique<std::ofstream>(opts::LinkSectionsFile, std::ios::out);
411a34c753fSRafael Auler     if (!LinkSectionsFile) {
41240c2e0faSMaksim Panchenko       errs() << "BOLT-ERROR: link sections file " << opts::LinkSectionsFile
41340c2e0faSMaksim Panchenko              << " cannot be opened\n";
414a34c753fSRafael Auler       exit(1);
415a34c753fSRafael Auler     }
416a34c753fSRafael Auler   }
417a34c753fSRafael Auler 
418a34c753fSRafael Auler   if (FuncsFile || LinkSectionsFile) {
419a34c753fSRafael Auler     std::vector<BinaryFunction *> SortedFunctions(BFs.size());
42040c2e0faSMaksim Panchenko     std::transform(BFs.begin(), BFs.end(), SortedFunctions.begin(),
421a34c753fSRafael Auler                    [](std::pair<const uint64_t, BinaryFunction> &BFI) {
422a34c753fSRafael Auler                      return &BFI.second;
423a34c753fSRafael Auler                    });
424a34c753fSRafael Auler 
425a34c753fSRafael Auler     // Sort functions by index.
426a34c753fSRafael Auler     std::stable_sort(
427a34c753fSRafael Auler       SortedFunctions.begin(),
428a34c753fSRafael Auler       SortedFunctions.end(),
429a34c753fSRafael Auler       [](const BinaryFunction *A, const BinaryFunction *B) {
430a34c753fSRafael Auler         if (A->hasValidIndex() && B->hasValidIndex()) {
431a34c753fSRafael Auler           return A->getIndex() < B->getIndex();
432a34c753fSRafael Auler         } else if (A->hasValidIndex() && !B->hasValidIndex()) {
433a34c753fSRafael Auler           return true;
434a34c753fSRafael Auler         } else if (!A->hasValidIndex() && B->hasValidIndex()) {
435a34c753fSRafael Auler           return false;
436a34c753fSRafael Auler         } else {
437a34c753fSRafael Auler           return A->getAddress() < B->getAddress();
438a34c753fSRafael Auler         }
439a34c753fSRafael Auler       });
440a34c753fSRafael Auler 
441a34c753fSRafael Auler     for (const BinaryFunction *Func : SortedFunctions) {
442a34c753fSRafael Auler       if (!Func->hasValidIndex())
443a34c753fSRafael Auler         break;
444a34c753fSRafael Auler       if (Func->isPLTFunction())
445a34c753fSRafael Auler         continue;
446a34c753fSRafael Auler 
447a34c753fSRafael Auler       if (FuncsFile)
448a34c753fSRafael Auler         *FuncsFile << Func->getOneName().str() << '\n';
449a34c753fSRafael Auler 
450a34c753fSRafael Auler       if (LinkSectionsFile) {
451a34c753fSRafael Auler         const char *Indent = "";
452a34c753fSRafael Auler         std::vector<StringRef> AllNames = Func->getNames();
453a34c753fSRafael Auler         std::sort(AllNames.begin(), AllNames.end());
454a34c753fSRafael Auler         for (StringRef Name : AllNames) {
455a34c753fSRafael Auler           const size_t SlashPos = Name.find('/');
456a34c753fSRafael Auler           if (SlashPos != std::string::npos) {
457a34c753fSRafael Auler             // Avoid duplicates for local functions.
458a34c753fSRafael Auler             if (Name.find('/', SlashPos + 1) != std::string::npos)
459a34c753fSRafael Auler               continue;
460a34c753fSRafael Auler             Name = Name.substr(0, SlashPos);
461a34c753fSRafael Auler           }
462a34c753fSRafael Auler           *LinkSectionsFile << Indent << ".text." << Name.str() << '\n';
463a34c753fSRafael Auler           Indent = " ";
464a34c753fSRafael Auler         }
465a34c753fSRafael Auler       }
466a34c753fSRafael Auler     }
467a34c753fSRafael Auler 
468a34c753fSRafael Auler     if (FuncsFile) {
469a34c753fSRafael Auler       FuncsFile->close();
470a34c753fSRafael Auler       outs() << "BOLT-INFO: dumped function order to "
471a34c753fSRafael Auler              << opts::GenerateFunctionOrderFile << '\n';
472a34c753fSRafael Auler     }
473a34c753fSRafael Auler 
474a34c753fSRafael Auler     if (LinkSectionsFile) {
475a34c753fSRafael Auler       LinkSectionsFile->close();
476a34c753fSRafael Auler       outs() << "BOLT-INFO: dumped linker section order to "
477a34c753fSRafael Auler              << opts::LinkSectionsFile << '\n';
478a34c753fSRafael Auler     }
479a34c753fSRafael Auler   }
480a34c753fSRafael Auler }
481a34c753fSRafael Auler 
482a34c753fSRafael Auler } // namespace bolt
483a34c753fSRafael Auler } // namespace llvm
484