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 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 131*fd960495SVladislav Khmelevsky // Assign valid index for functions with valid profile. 132*fd960495SVladislav Khmelevsky for (auto &It : BFs) { 133*fd960495SVladislav Khmelevsky BinaryFunction &BF = It.second; 134*fd960495SVladislav Khmelevsky if (!BF.hasValidIndex() && BF.hasValidProfile()) 135*fd960495SVladislav Khmelevsky BF.setIndex(Index++); 136*fd960495SVladislav Khmelevsky } 137*fd960495SVladislav 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 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 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; 295a34c753fSRafael Auler std::transform(BFs.begin(), 296a34c753fSRafael Auler BFs.end(), 297a34c753fSRafael Auler SortedFunctions.begin(), 298a34c753fSRafael Auler [](std::pair<const uint64_t, BinaryFunction> &BFI) { 299a34c753fSRafael Auler return &BFI.second; 300a34c753fSRafael Auler }); 301a34c753fSRafael Auler std::stable_sort(SortedFunctions.begin(), SortedFunctions.end(), 302a34c753fSRafael Auler [&](const BinaryFunction *A, const BinaryFunction *B) { 303a34c753fSRafael Auler if (A->isIgnored()) 304a34c753fSRafael Auler return false; 305a34c753fSRafael Auler const size_t PadA = opts::padFunction(*A); 306a34c753fSRafael Auler const size_t PadB = opts::padFunction(*B); 307a34c753fSRafael Auler if (!PadA || !PadB) { 308a34c753fSRafael Auler if (PadA) 309a34c753fSRafael Auler return true; 310a34c753fSRafael Auler if (PadB) 311a34c753fSRafael Auler return false; 312a34c753fSRafael Auler } 313a34c753fSRafael Auler return !A->hasProfile() && 314a34c753fSRafael Auler (B->hasProfile() || 315a34c753fSRafael Auler (A->getExecutionCount() > B->getExecutionCount())); 316a34c753fSRafael Auler }); 317f92ab6afSAmir Ayupov for (BinaryFunction *BF : SortedFunctions) 318a34c753fSRafael Auler if (BF->hasProfile()) 319a34c753fSRafael Auler BF->setIndex(Index++); 320a34c753fSRafael Auler } 321a34c753fSRafael Auler break; 322a34c753fSRafael Auler case RT_HFSORT: 323a34c753fSRafael Auler Clusters = clusterize(Cg); 324a34c753fSRafael Auler break; 325a34c753fSRafael Auler case RT_HFSORT_PLUS: 326a34c753fSRafael Auler Clusters = hfsortPlus(Cg); 327a34c753fSRafael Auler break; 328a34c753fSRafael Auler case RT_PETTIS_HANSEN: 329a34c753fSRafael Auler Clusters = pettisAndHansen(Cg); 330a34c753fSRafael Auler break; 331a34c753fSRafael Auler case RT_RANDOM: 332a34c753fSRafael Auler std::srand(opts::RandomSeed); 333a34c753fSRafael Auler Clusters = randomClusters(Cg); 334a34c753fSRafael Auler break; 335a34c753fSRafael Auler case RT_USER: 336a34c753fSRafael Auler { 337a34c753fSRafael Auler uint32_t Index = 0; 338a34c753fSRafael Auler for (const std::string &Function : readFunctionOrderFile()) { 339a34c753fSRafael Auler std::vector<uint64_t> FuncAddrs; 340a34c753fSRafael Auler 341a34c753fSRafael Auler BinaryData *BD = BC.getBinaryDataByName(Function); 342a34c753fSRafael Auler if (!BD) { 343a34c753fSRafael Auler uint32_t LocalID = 1; 344a34c753fSRafael Auler while(1) { 345a34c753fSRafael Auler // If we can't find the main symbol name, look for alternates. 346a34c753fSRafael Auler const std::string FuncName = 347a34c753fSRafael Auler Function + "/" + std::to_string(LocalID); 348a34c753fSRafael Auler BD = BC.getBinaryDataByName(FuncName); 349a34c753fSRafael Auler if (BD) 350a34c753fSRafael Auler FuncAddrs.push_back(BD->getAddress()); 351a34c753fSRafael Auler else 352a34c753fSRafael Auler break; 353a34c753fSRafael Auler LocalID++; 354a34c753fSRafael Auler } 355a34c753fSRafael Auler } else { 356a34c753fSRafael Auler FuncAddrs.push_back(BD->getAddress()); 357a34c753fSRafael Auler } 358a34c753fSRafael Auler 359a34c753fSRafael Auler if (FuncAddrs.empty()) { 360a34c753fSRafael Auler errs() << "BOLT-WARNING: Reorder functions: can't find function for " 361a34c753fSRafael Auler << Function << ".\n"; 362a34c753fSRafael Auler continue; 363a34c753fSRafael Auler } 364a34c753fSRafael Auler 365a34c753fSRafael Auler for (const uint64_t FuncAddr : FuncAddrs) { 366a34c753fSRafael Auler const BinaryData *FuncBD = BC.getBinaryDataAtAddress(FuncAddr); 367a34c753fSRafael Auler assert(FuncBD); 368a34c753fSRafael Auler 369a34c753fSRafael Auler BinaryFunction *BF = BC.getFunctionForSymbol(FuncBD->getSymbol()); 370a34c753fSRafael Auler if (!BF) { 371a34c753fSRafael Auler errs() << "BOLT-WARNING: Reorder functions: can't find function for " 372a34c753fSRafael Auler << Function << ".\n"; 373a34c753fSRafael Auler break; 374a34c753fSRafael Auler } 375f92ab6afSAmir Ayupov if (!BF->hasValidIndex()) 376a34c753fSRafael Auler BF->setIndex(Index++); 377f92ab6afSAmir Ayupov else if (opts::Verbosity > 0) 378a34c753fSRafael Auler errs() << "BOLT-WARNING: Duplicate reorder entry for " << Function 379a34c753fSRafael Auler << ".\n"; 380a34c753fSRafael Auler } 381a34c753fSRafael Auler } 382a34c753fSRafael Auler } 383a34c753fSRafael Auler break; 384a34c753fSRafael Auler } 385a34c753fSRafael Auler 386a34c753fSRafael Auler reorder(std::move(Clusters), BFs); 387a34c753fSRafael Auler 388a34c753fSRafael Auler std::unique_ptr<std::ofstream> FuncsFile; 389a34c753fSRafael Auler if (!opts::GenerateFunctionOrderFile.empty()) { 39040c2e0faSMaksim Panchenko FuncsFile = std::make_unique<std::ofstream>(opts::GenerateFunctionOrderFile, 391a34c753fSRafael Auler std::ios::out); 392a34c753fSRafael Auler if (!FuncsFile) { 393a34c753fSRafael Auler errs() << "BOLT-ERROR: ordered functions file " 394a34c753fSRafael Auler << opts::GenerateFunctionOrderFile << " cannot be opened\n"; 395a34c753fSRafael Auler exit(1); 396a34c753fSRafael Auler } 397a34c753fSRafael Auler } 398a34c753fSRafael Auler 399a34c753fSRafael Auler std::unique_ptr<std::ofstream> LinkSectionsFile; 400a34c753fSRafael Auler if (!opts::LinkSectionsFile.empty()) { 401a34c753fSRafael Auler LinkSectionsFile = 40240c2e0faSMaksim Panchenko std::make_unique<std::ofstream>(opts::LinkSectionsFile, std::ios::out); 403a34c753fSRafael Auler if (!LinkSectionsFile) { 40440c2e0faSMaksim Panchenko errs() << "BOLT-ERROR: link sections file " << opts::LinkSectionsFile 40540c2e0faSMaksim Panchenko << " cannot be opened\n"; 406a34c753fSRafael Auler exit(1); 407a34c753fSRafael Auler } 408a34c753fSRafael Auler } 409a34c753fSRafael Auler 410a34c753fSRafael Auler if (FuncsFile || LinkSectionsFile) { 411a34c753fSRafael Auler std::vector<BinaryFunction *> SortedFunctions(BFs.size()); 41240c2e0faSMaksim Panchenko std::transform(BFs.begin(), BFs.end(), SortedFunctions.begin(), 413a34c753fSRafael Auler [](std::pair<const uint64_t, BinaryFunction> &BFI) { 414a34c753fSRafael Auler return &BFI.second; 415a34c753fSRafael Auler }); 416a34c753fSRafael Auler 417a34c753fSRafael Auler // Sort functions by index. 418a34c753fSRafael Auler std::stable_sort( 419a34c753fSRafael Auler SortedFunctions.begin(), 420a34c753fSRafael Auler SortedFunctions.end(), 421a34c753fSRafael Auler [](const BinaryFunction *A, const BinaryFunction *B) { 422f92ab6afSAmir Ayupov if (A->hasValidIndex() && B->hasValidIndex()) 423a34c753fSRafael Auler return A->getIndex() < B->getIndex(); 424f92ab6afSAmir Ayupov if (A->hasValidIndex() && !B->hasValidIndex()) 425a34c753fSRafael Auler return true; 426f92ab6afSAmir Ayupov if (!A->hasValidIndex() && B->hasValidIndex()) 427a34c753fSRafael Auler return false; 428a34c753fSRafael Auler return A->getAddress() < B->getAddress(); 429a34c753fSRafael Auler }); 430a34c753fSRafael Auler 431a34c753fSRafael Auler for (const BinaryFunction *Func : SortedFunctions) { 432a34c753fSRafael Auler if (!Func->hasValidIndex()) 433a34c753fSRafael Auler break; 434a34c753fSRafael Auler if (Func->isPLTFunction()) 435a34c753fSRafael Auler continue; 436a34c753fSRafael Auler 437a34c753fSRafael Auler if (FuncsFile) 438a34c753fSRafael Auler *FuncsFile << Func->getOneName().str() << '\n'; 439a34c753fSRafael Auler 440a34c753fSRafael Auler if (LinkSectionsFile) { 441a34c753fSRafael Auler const char *Indent = ""; 442a34c753fSRafael Auler std::vector<StringRef> AllNames = Func->getNames(); 443a34c753fSRafael Auler std::sort(AllNames.begin(), AllNames.end()); 444a34c753fSRafael Auler for (StringRef Name : AllNames) { 445a34c753fSRafael Auler const size_t SlashPos = Name.find('/'); 446a34c753fSRafael Auler if (SlashPos != std::string::npos) { 447a34c753fSRafael Auler // Avoid duplicates for local functions. 448a34c753fSRafael Auler if (Name.find('/', SlashPos + 1) != std::string::npos) 449a34c753fSRafael Auler continue; 450a34c753fSRafael Auler Name = Name.substr(0, SlashPos); 451a34c753fSRafael Auler } 452a34c753fSRafael Auler *LinkSectionsFile << Indent << ".text." << Name.str() << '\n'; 453a34c753fSRafael Auler Indent = " "; 454a34c753fSRafael Auler } 455a34c753fSRafael Auler } 456a34c753fSRafael Auler } 457a34c753fSRafael Auler 458a34c753fSRafael Auler if (FuncsFile) { 459a34c753fSRafael Auler FuncsFile->close(); 460a34c753fSRafael Auler outs() << "BOLT-INFO: dumped function order to " 461a34c753fSRafael Auler << opts::GenerateFunctionOrderFile << '\n'; 462a34c753fSRafael Auler } 463a34c753fSRafael Auler 464a34c753fSRafael Auler if (LinkSectionsFile) { 465a34c753fSRafael Auler LinkSectionsFile->close(); 466a34c753fSRafael Auler outs() << "BOLT-INFO: dumped linker section order to " 467a34c753fSRafael Auler << opts::LinkSectionsFile << '\n'; 468a34c753fSRafael Auler } 469a34c753fSRafael Auler } 470a34c753fSRafael Auler } 471a34c753fSRafael Auler 472a34c753fSRafael Auler } // namespace bolt 473a34c753fSRafael Auler } // namespace llvm 474