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