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