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 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; 162*f92ab6afSAmir Ayupov if (PrintDetailed) 163a34c753fSRafael Auler outs() << "BOLT-INFO: Function reordering page layout\n" 164a34c753fSRafael Auler << "BOLT-INFO: ============== page 0 ==============\n"; 165a34c753fSRafael Auler for (Cluster &Cluster : Clusters) { 166*f92ab6afSAmir Ayupov if (PrintDetailed) 16740c2e0faSMaksim Panchenko outs() << format( 16840c2e0faSMaksim Panchenko "BOLT-INFO: -------- density = %.3lf (%u / %u) --------\n", 169a34c753fSRafael Auler Cluster.density(), Cluster.samples(), Cluster.size()); 170a34c753fSRafael Auler 171a34c753fSRafael Auler for (NodeId FuncId : Cluster.targets()) { 172a34c753fSRafael Auler if (Cg.samples(FuncId) > 0) { 173a34c753fSRafael Auler Hotfuncs++; 174a34c753fSRafael Auler 175*f92ab6afSAmir Ayupov if (PrintDetailed) 17640c2e0faSMaksim Panchenko outs() << "BOLT-INFO: hot func " << *Cg.nodeIdToFunc(FuncId) << " (" 17740c2e0faSMaksim Panchenko << Cg.size(FuncId) << ")\n"; 178a34c753fSRafael Auler 179a34c753fSRafael Auler uint64_t Dist = 0; 180a34c753fSRafael Auler uint64_t Calls = 0; 181a34c753fSRafael Auler for (NodeId Dst : Cg.successors(FuncId)) { 182a34c753fSRafael Auler if (FuncId == Dst) // ignore recursive calls in stats 183a34c753fSRafael Auler continue; 184a34c753fSRafael Auler const Arc &Arc = *Cg.findArc(FuncId, Dst); 185a34c753fSRafael Auler const auto D = std::abs(FuncAddr[Arc.dst()] - 186a34c753fSRafael Auler (FuncAddr[FuncId] + Arc.avgCallOffset())); 187a34c753fSRafael Auler const double W = Arc.weight(); 188*f92ab6afSAmir Ayupov if (D < 64 && PrintDetailed && opts::Verbosity > 2) 189a34c753fSRafael Auler outs() << "BOLT-INFO: short (" << D << "B) call:\n" 190a34c753fSRafael Auler << "BOLT-INFO: Src: " << *Cg.nodeIdToFunc(FuncId) << "\n" 191a34c753fSRafael Auler << "BOLT-INFO: Dst: " << *Cg.nodeIdToFunc(Dst) << "\n" 192a34c753fSRafael Auler << "BOLT-INFO: Weight = " << W << "\n" 193a34c753fSRafael Auler << "BOLT-INFO: AvgOffset = " << Arc.avgCallOffset() << "\n"; 194a34c753fSRafael Auler Calls += W; 195a34c753fSRafael Auler if (D < 64) TotalCalls64B += W; 196a34c753fSRafael Auler if (D < 4096) TotalCalls4KB += W; 197a34c753fSRafael Auler if (D < (2 << 20)) TotalCalls2MB += W; 198a34c753fSRafael Auler Dist += Arc.weight() * D; 199*f92ab6afSAmir Ayupov if (PrintDetailed) 200a34c753fSRafael Auler outs() << format("BOLT-INFO: arc: %u [@%lu+%.1lf] -> %u [@%lu]: " 201a34c753fSRafael Auler "weight = %.0lf, callDist = %f\n", 202a34c753fSRafael Auler Arc.src(), 203a34c753fSRafael Auler FuncAddr[Arc.src()], 204a34c753fSRafael Auler Arc.avgCallOffset(), 205a34c753fSRafael Auler Arc.dst(), 206a34c753fSRafael Auler FuncAddr[Arc.dst()], 207a34c753fSRafael Auler Arc.weight(), D); 208a34c753fSRafael Auler } 209a34c753fSRafael Auler TotalCalls += Calls; 210a34c753fSRafael Auler TotalDistance += Dist; 211a34c753fSRafael Auler TotalSize += Cg.size(FuncId); 212a34c753fSRafael Auler 213a34c753fSRafael Auler if (PrintDetailed) { 214a34c753fSRafael Auler outs() << format("BOLT-INFO: start = %6u : avgCallDist = %lu : ", 21540c2e0faSMaksim Panchenko TotalSize, Calls ? Dist / Calls : 0) 216a34c753fSRafael Auler << Cg.nodeIdToFunc(FuncId)->getPrintName() << '\n'; 217a34c753fSRafael Auler const uint64_t NewPage = TotalSize / HugePageSize; 218a34c753fSRafael Auler if (NewPage != CurPage) { 219a34c753fSRafael Auler CurPage = NewPage; 22040c2e0faSMaksim Panchenko outs() << format( 22140c2e0faSMaksim Panchenko "BOLT-INFO: ============== page %u ==============\n", CurPage); 222a34c753fSRafael Auler } 223a34c753fSRafael Auler } 224a34c753fSRafael Auler } 225a34c753fSRafael Auler } 226a34c753fSRafael Auler } 227a34c753fSRafael Auler outs() << "BOLT-INFO: Function reordering stats\n" 228a34c753fSRafael Auler << format("BOLT-INFO: Number of hot functions: %u\n" 229a34c753fSRafael Auler "BOLT-INFO: Number of clusters: %lu\n", 230a34c753fSRafael Auler Hotfuncs, Clusters.size()) 231a34c753fSRafael Auler << format("BOLT-INFO: Final average call distance = %.1lf " 232a34c753fSRafael Auler "(%.0lf / %.0lf)\n", 23340c2e0faSMaksim Panchenko TotalCalls ? TotalDistance / TotalCalls : 0, TotalDistance, 23440c2e0faSMaksim Panchenko TotalCalls) 235a34c753fSRafael Auler << format("BOLT-INFO: Total Calls = %.0lf\n", TotalCalls); 236*f92ab6afSAmir Ayupov if (TotalCalls) 237a34c753fSRafael Auler outs() << format("BOLT-INFO: Total Calls within 64B = %.0lf (%.2lf%%)\n", 238a34c753fSRafael Auler TotalCalls64B, 100 * TotalCalls64B / TotalCalls) 239a34c753fSRafael Auler << format("BOLT-INFO: Total Calls within 4KB = %.0lf (%.2lf%%)\n", 240a34c753fSRafael Auler TotalCalls4KB, 100 * TotalCalls4KB / TotalCalls) 241a34c753fSRafael Auler << format("BOLT-INFO: Total Calls within 2MB = %.0lf (%.2lf%%)\n", 242a34c753fSRafael Auler TotalCalls2MB, 100 * TotalCalls2MB / TotalCalls); 243a34c753fSRafael Auler } 244a34c753fSRafael Auler 245a34c753fSRafael Auler namespace { 246a34c753fSRafael Auler 247a34c753fSRafael Auler std::vector<std::string> readFunctionOrderFile() { 248a34c753fSRafael Auler std::vector<std::string> FunctionNames; 249a34c753fSRafael Auler std::ifstream FuncsFile(opts::FunctionOrderFile, std::ios::in); 250a34c753fSRafael Auler if (!FuncsFile) { 251a34c753fSRafael Auler errs() << "Ordered functions file \"" << opts::FunctionOrderFile 252a34c753fSRafael Auler << "\" can't be opened.\n"; 253a34c753fSRafael Auler exit(1); 254a34c753fSRafael Auler } 255a34c753fSRafael Auler std::string FuncName; 256*f92ab6afSAmir Ayupov while (std::getline(FuncsFile, FuncName)) 257a34c753fSRafael Auler FunctionNames.push_back(FuncName); 258a34c753fSRafael Auler return FunctionNames; 259a34c753fSRafael Auler } 260a34c753fSRafael Auler 261a34c753fSRafael Auler } 262a34c753fSRafael Auler 263a34c753fSRafael Auler void ReorderFunctions::runOnFunctions(BinaryContext &BC) { 264a34c753fSRafael Auler auto &BFs = BC.getBinaryFunctions(); 265a34c753fSRafael Auler if (opts::ReorderFunctions != RT_NONE && 266a34c753fSRafael Auler opts::ReorderFunctions != RT_EXEC_COUNT && 267a34c753fSRafael Auler opts::ReorderFunctions != RT_USER) { 268a34c753fSRafael Auler Cg = buildCallGraph(BC, 269a34c753fSRafael Auler [](const BinaryFunction &BF) { 270a34c753fSRafael Auler if (!BF.hasProfile()) 271a34c753fSRafael Auler return true; 272a34c753fSRafael Auler if (BF.getState() != BinaryFunction::State::CFG) 273a34c753fSRafael Auler return true; 274a34c753fSRafael Auler return false; 275a34c753fSRafael Auler }, 276a34c753fSRafael Auler opts::CgFromPerfData, 277a34c753fSRafael Auler false, // IncludeColdCalls 278a34c753fSRafael Auler opts::ReorderFunctionsUseHotSize, 279a34c753fSRafael Auler opts::CgUseSplitHotSize, 280a34c753fSRafael Auler opts::UseEdgeCounts, 281a34c753fSRafael Auler opts::CgIgnoreRecursiveCalls); 282a34c753fSRafael Auler Cg.normalizeArcWeights(); 283a34c753fSRafael Auler } 284a34c753fSRafael Auler 285a34c753fSRafael Auler std::vector<Cluster> Clusters; 286a34c753fSRafael Auler 287a34c753fSRafael Auler switch (opts::ReorderFunctions) { 288a34c753fSRafael Auler case RT_NONE: 289a34c753fSRafael Auler break; 290a34c753fSRafael Auler case RT_EXEC_COUNT: 291a34c753fSRafael Auler { 292a34c753fSRafael Auler std::vector<BinaryFunction *> SortedFunctions(BFs.size()); 293a34c753fSRafael Auler uint32_t Index = 0; 294a34c753fSRafael Auler std::transform(BFs.begin(), 295a34c753fSRafael Auler BFs.end(), 296a34c753fSRafael Auler SortedFunctions.begin(), 297a34c753fSRafael Auler [](std::pair<const uint64_t, BinaryFunction> &BFI) { 298a34c753fSRafael Auler return &BFI.second; 299a34c753fSRafael Auler }); 300a34c753fSRafael Auler std::stable_sort(SortedFunctions.begin(), SortedFunctions.end(), 301a34c753fSRafael Auler [&](const BinaryFunction *A, const BinaryFunction *B) { 302a34c753fSRafael Auler if (A->isIgnored()) 303a34c753fSRafael Auler return false; 304a34c753fSRafael Auler const size_t PadA = opts::padFunction(*A); 305a34c753fSRafael Auler const size_t PadB = opts::padFunction(*B); 306a34c753fSRafael Auler if (!PadA || !PadB) { 307a34c753fSRafael Auler if (PadA) 308a34c753fSRafael Auler return true; 309a34c753fSRafael Auler if (PadB) 310a34c753fSRafael Auler return false; 311a34c753fSRafael Auler } 312a34c753fSRafael Auler return !A->hasProfile() && 313a34c753fSRafael Auler (B->hasProfile() || 314a34c753fSRafael Auler (A->getExecutionCount() > B->getExecutionCount())); 315a34c753fSRafael Auler }); 316*f92ab6afSAmir Ayupov for (BinaryFunction *BF : SortedFunctions) 317a34c753fSRafael Auler if (BF->hasProfile()) 318a34c753fSRafael Auler BF->setIndex(Index++); 319a34c753fSRafael Auler } 320a34c753fSRafael Auler break; 321a34c753fSRafael Auler case RT_HFSORT: 322a34c753fSRafael Auler Clusters = clusterize(Cg); 323a34c753fSRafael Auler break; 324a34c753fSRafael Auler case RT_HFSORT_PLUS: 325a34c753fSRafael Auler Clusters = hfsortPlus(Cg); 326a34c753fSRafael Auler break; 327a34c753fSRafael Auler case RT_PETTIS_HANSEN: 328a34c753fSRafael Auler Clusters = pettisAndHansen(Cg); 329a34c753fSRafael Auler break; 330a34c753fSRafael Auler case RT_RANDOM: 331a34c753fSRafael Auler std::srand(opts::RandomSeed); 332a34c753fSRafael Auler Clusters = randomClusters(Cg); 333a34c753fSRafael Auler break; 334a34c753fSRafael Auler case RT_USER: 335a34c753fSRafael Auler { 336a34c753fSRafael Auler uint32_t Index = 0; 337a34c753fSRafael Auler for (const std::string &Function : readFunctionOrderFile()) { 338a34c753fSRafael Auler std::vector<uint64_t> FuncAddrs; 339a34c753fSRafael Auler 340a34c753fSRafael Auler BinaryData *BD = BC.getBinaryDataByName(Function); 341a34c753fSRafael Auler if (!BD) { 342a34c753fSRafael Auler uint32_t LocalID = 1; 343a34c753fSRafael Auler while(1) { 344a34c753fSRafael Auler // If we can't find the main symbol name, look for alternates. 345a34c753fSRafael Auler const std::string FuncName = 346a34c753fSRafael Auler Function + "/" + std::to_string(LocalID); 347a34c753fSRafael Auler BD = BC.getBinaryDataByName(FuncName); 348a34c753fSRafael Auler if (BD) 349a34c753fSRafael Auler FuncAddrs.push_back(BD->getAddress()); 350a34c753fSRafael Auler else 351a34c753fSRafael Auler break; 352a34c753fSRafael Auler LocalID++; 353a34c753fSRafael Auler } 354a34c753fSRafael Auler } else { 355a34c753fSRafael Auler FuncAddrs.push_back(BD->getAddress()); 356a34c753fSRafael Auler } 357a34c753fSRafael Auler 358a34c753fSRafael Auler if (FuncAddrs.empty()) { 359a34c753fSRafael Auler errs() << "BOLT-WARNING: Reorder functions: can't find function for " 360a34c753fSRafael Auler << Function << ".\n"; 361a34c753fSRafael Auler continue; 362a34c753fSRafael Auler } 363a34c753fSRafael Auler 364a34c753fSRafael Auler for (const uint64_t FuncAddr : FuncAddrs) { 365a34c753fSRafael Auler const BinaryData *FuncBD = BC.getBinaryDataAtAddress(FuncAddr); 366a34c753fSRafael Auler assert(FuncBD); 367a34c753fSRafael Auler 368a34c753fSRafael Auler BinaryFunction *BF = BC.getFunctionForSymbol(FuncBD->getSymbol()); 369a34c753fSRafael Auler if (!BF) { 370a34c753fSRafael Auler errs() << "BOLT-WARNING: Reorder functions: can't find function for " 371a34c753fSRafael Auler << Function << ".\n"; 372a34c753fSRafael Auler break; 373a34c753fSRafael Auler } 374*f92ab6afSAmir Ayupov if (!BF->hasValidIndex()) 375a34c753fSRafael Auler BF->setIndex(Index++); 376*f92ab6afSAmir Ayupov else if (opts::Verbosity > 0) 377a34c753fSRafael Auler errs() << "BOLT-WARNING: Duplicate reorder entry for " << Function 378a34c753fSRafael Auler << ".\n"; 379a34c753fSRafael Auler } 380a34c753fSRafael Auler } 381a34c753fSRafael Auler } 382a34c753fSRafael Auler break; 383a34c753fSRafael Auler } 384a34c753fSRafael Auler 385a34c753fSRafael Auler reorder(std::move(Clusters), BFs); 386a34c753fSRafael Auler 387a34c753fSRafael Auler std::unique_ptr<std::ofstream> FuncsFile; 388a34c753fSRafael Auler if (!opts::GenerateFunctionOrderFile.empty()) { 38940c2e0faSMaksim Panchenko FuncsFile = std::make_unique<std::ofstream>(opts::GenerateFunctionOrderFile, 390a34c753fSRafael Auler std::ios::out); 391a34c753fSRafael Auler if (!FuncsFile) { 392a34c753fSRafael Auler errs() << "BOLT-ERROR: ordered functions file " 393a34c753fSRafael Auler << opts::GenerateFunctionOrderFile << " cannot be opened\n"; 394a34c753fSRafael Auler exit(1); 395a34c753fSRafael Auler } 396a34c753fSRafael Auler } 397a34c753fSRafael Auler 398a34c753fSRafael Auler std::unique_ptr<std::ofstream> LinkSectionsFile; 399a34c753fSRafael Auler if (!opts::LinkSectionsFile.empty()) { 400a34c753fSRafael Auler LinkSectionsFile = 40140c2e0faSMaksim Panchenko std::make_unique<std::ofstream>(opts::LinkSectionsFile, std::ios::out); 402a34c753fSRafael Auler if (!LinkSectionsFile) { 40340c2e0faSMaksim Panchenko errs() << "BOLT-ERROR: link sections file " << opts::LinkSectionsFile 40440c2e0faSMaksim Panchenko << " cannot be opened\n"; 405a34c753fSRafael Auler exit(1); 406a34c753fSRafael Auler } 407a34c753fSRafael Auler } 408a34c753fSRafael Auler 409a34c753fSRafael Auler if (FuncsFile || LinkSectionsFile) { 410a34c753fSRafael Auler std::vector<BinaryFunction *> SortedFunctions(BFs.size()); 41140c2e0faSMaksim Panchenko std::transform(BFs.begin(), BFs.end(), SortedFunctions.begin(), 412a34c753fSRafael Auler [](std::pair<const uint64_t, BinaryFunction> &BFI) { 413a34c753fSRafael Auler return &BFI.second; 414a34c753fSRafael Auler }); 415a34c753fSRafael Auler 416a34c753fSRafael Auler // Sort functions by index. 417a34c753fSRafael Auler std::stable_sort( 418a34c753fSRafael Auler SortedFunctions.begin(), 419a34c753fSRafael Auler SortedFunctions.end(), 420a34c753fSRafael Auler [](const BinaryFunction *A, const BinaryFunction *B) { 421*f92ab6afSAmir Ayupov if (A->hasValidIndex() && B->hasValidIndex()) 422a34c753fSRafael Auler return A->getIndex() < B->getIndex(); 423*f92ab6afSAmir Ayupov if (A->hasValidIndex() && !B->hasValidIndex()) 424a34c753fSRafael Auler return true; 425*f92ab6afSAmir Ayupov if (!A->hasValidIndex() && B->hasValidIndex()) 426a34c753fSRafael Auler return false; 427a34c753fSRafael Auler return A->getAddress() < B->getAddress(); 428a34c753fSRafael Auler }); 429a34c753fSRafael Auler 430a34c753fSRafael Auler for (const BinaryFunction *Func : SortedFunctions) { 431a34c753fSRafael Auler if (!Func->hasValidIndex()) 432a34c753fSRafael Auler break; 433a34c753fSRafael Auler if (Func->isPLTFunction()) 434a34c753fSRafael Auler continue; 435a34c753fSRafael Auler 436a34c753fSRafael Auler if (FuncsFile) 437a34c753fSRafael Auler *FuncsFile << Func->getOneName().str() << '\n'; 438a34c753fSRafael Auler 439a34c753fSRafael Auler if (LinkSectionsFile) { 440a34c753fSRafael Auler const char *Indent = ""; 441a34c753fSRafael Auler std::vector<StringRef> AllNames = Func->getNames(); 442a34c753fSRafael Auler std::sort(AllNames.begin(), AllNames.end()); 443a34c753fSRafael Auler for (StringRef Name : AllNames) { 444a34c753fSRafael Auler const size_t SlashPos = Name.find('/'); 445a34c753fSRafael Auler if (SlashPos != std::string::npos) { 446a34c753fSRafael Auler // Avoid duplicates for local functions. 447a34c753fSRafael Auler if (Name.find('/', SlashPos + 1) != std::string::npos) 448a34c753fSRafael Auler continue; 449a34c753fSRafael Auler Name = Name.substr(0, SlashPos); 450a34c753fSRafael Auler } 451a34c753fSRafael Auler *LinkSectionsFile << Indent << ".text." << Name.str() << '\n'; 452a34c753fSRafael Auler Indent = " "; 453a34c753fSRafael Auler } 454a34c753fSRafael Auler } 455a34c753fSRafael Auler } 456a34c753fSRafael Auler 457a34c753fSRafael Auler if (FuncsFile) { 458a34c753fSRafael Auler FuncsFile->close(); 459a34c753fSRafael Auler outs() << "BOLT-INFO: dumped function order to " 460a34c753fSRafael Auler << opts::GenerateFunctionOrderFile << '\n'; 461a34c753fSRafael Auler } 462a34c753fSRafael Auler 463a34c753fSRafael Auler if (LinkSectionsFile) { 464a34c753fSRafael Auler LinkSectionsFile->close(); 465a34c753fSRafael Auler outs() << "BOLT-INFO: dumped linker section order to " 466a34c753fSRafael Auler << opts::LinkSectionsFile << '\n'; 467a34c753fSRafael Auler } 468a34c753fSRafael Auler } 469a34c753fSRafael Auler } 470a34c753fSRafael Auler 471a34c753fSRafael Auler } // namespace bolt 472a34c753fSRafael Auler } // namespace llvm 473