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