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