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