diff options
Diffstat (limited to 'contrib/llvm-project/lld/MachO/SectionPriorities.cpp')
-rw-r--r-- | contrib/llvm-project/lld/MachO/SectionPriorities.cpp | 108 |
1 files changed, 57 insertions, 51 deletions
diff --git a/contrib/llvm-project/lld/MachO/SectionPriorities.cpp b/contrib/llvm-project/lld/MachO/SectionPriorities.cpp index 35510d7338e8..ac4878343ac0 100644 --- a/contrib/llvm-project/lld/MachO/SectionPriorities.cpp +++ b/contrib/llvm-project/lld/MachO/SectionPriorities.cpp @@ -16,6 +16,7 @@ #include "InputFiles.h" #include "Symbols.h" #include "Target.h" + #include "lld/Common/Args.h" #include "lld/Common/CommonLinkerContext.h" #include "lld/Common/ErrorHandler.h" @@ -33,7 +34,12 @@ using namespace llvm::sys; using namespace lld; using namespace lld::macho; +PriorityBuilder macho::priorityBuilder; + namespace { + +size_t highestAvailablePriority = std::numeric_limits<size_t>::max(); + struct Edge { int from; uint64_t weight; @@ -58,7 +64,7 @@ struct Cluster { class CallGraphSort { public: - CallGraphSort(); + CallGraphSort(const MapVector<SectionPair, uint64_t> &profile); DenseMap<const InputSection *, size_t> run(); @@ -71,13 +77,9 @@ private: constexpr int MAX_DENSITY_DEGRADATION = 8; } // end anonymous namespace -using SectionPair = std::pair<const InputSection *, const InputSection *>; - -// Take the edge list in config->callGraphProfile, resolve symbol names to -// Symbols, and generate a graph between InputSections with the provided -// weights. -CallGraphSort::CallGraphSort() { - MapVector<SectionPair, uint64_t> &profile = config->callGraphProfile; +// Take the edge list in callGraphProfile, resolve symbol names to Symbols, and +// generate a graph between InputSections with the provided weights. +CallGraphSort::CallGraphSort(const MapVector<SectionPair, uint64_t> &profile) { DenseMap<const InputSection *, int> secToCluster; auto getOrCreateCluster = [&](const InputSection *isec) -> int { @@ -90,7 +92,7 @@ CallGraphSort::CallGraphSort() { }; // Create the graph - for (std::pair<SectionPair, uint64_t> &c : profile) { + for (const std::pair<SectionPair, uint64_t> &c : profile) { const auto fromSec = c.first.first->canonical(); const auto toSec = c.first.second->canonical(); uint64_t weight = c.second; @@ -208,7 +210,7 @@ DenseMap<const InputSection *, size_t> CallGraphSort::run() { // priority 0 and be placed at the end of sections. // NB: This is opposite from COFF/ELF to be compatible with the existing // order-file code. - int curOrder = clusters.size(); + int curOrder = highestAvailablePriority; for (int leader : sorted) { for (int i = leader;;) { orderMap[sections[i]] = curOrder--; @@ -247,8 +249,17 @@ DenseMap<const InputSection *, size_t> CallGraphSort::run() { return orderMap; } -static size_t getSymbolPriority(const SymbolPriorityEntry &entry, - const InputFile *f) { +Optional<size_t> macho::PriorityBuilder::getSymbolPriority(const Defined *sym) { + if (sym->isAbsolute()) + return None; + + auto it = priorities.find(sym->getName()); + if (it == priorities.end()) + return None; + const SymbolPriorityEntry &entry = it->second; + const InputFile *f = sym->isec->getFile(); + if (!f) + return entry.anyObjectFile; // We don't use toString(InputFile *) here because it returns the full path // for object files, and we only want the basename. StringRef filename; @@ -260,8 +271,9 @@ static size_t getSymbolPriority(const SymbolPriorityEntry &entry, return std::max(entry.objectFiles.lookup(filename), entry.anyObjectFile); } -void macho::extractCallGraphProfile() { +void macho::PriorityBuilder::extractCallGraphProfile() { TimeTraceScope timeScope("Extract call graph profile"); + bool hasOrderFile = !priorities.empty(); for (const InputFile *file : inputFiles) { auto *obj = dyn_cast_or_null<ObjFile>(file); if (!obj) @@ -271,15 +283,17 @@ void macho::extractCallGraphProfile() { entry.toIndex < obj->symbols.size()); auto *fromSym = dyn_cast_or_null<Defined>(obj->symbols[entry.fromIndex]); auto *toSym = dyn_cast_or_null<Defined>(obj->symbols[entry.toIndex]); - - if (!fromSym || !toSym) - continue; - config->callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count; + if (fromSym && toSym && + (!hasOrderFile || + (!getSymbolPriority(fromSym) && !getSymbolPriority(toSym)))) + callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count; } } } -void macho::parseOrderFile(StringRef path) { +void macho::PriorityBuilder::parseOrderFile(StringRef path) { + assert(callGraphProfile.empty() && + "Order file must be parsed before call graph profile is processed"); Optional<MemoryBufferRef> buffer = readFile(path); if (!buffer) { error("Could not read order file at " + path); @@ -287,7 +301,6 @@ void macho::parseOrderFile(StringRef path) { } MemoryBufferRef mbref = *buffer; - size_t priority = std::numeric_limits<size_t>::max(); for (StringRef line : args::getLines(mbref)) { StringRef objectFile, symbol; line = line.take_until([](char c) { return c == '#'; }); // ignore comments @@ -322,49 +335,42 @@ void macho::parseOrderFile(StringRef path) { symbol = line.trim(); if (!symbol.empty()) { - SymbolPriorityEntry &entry = config->priorities[symbol]; + SymbolPriorityEntry &entry = priorities[symbol]; if (!objectFile.empty()) - entry.objectFiles.insert(std::make_pair(objectFile, priority)); + entry.objectFiles.insert( + std::make_pair(objectFile, highestAvailablePriority)); else - entry.anyObjectFile = std::max(entry.anyObjectFile, priority); + entry.anyObjectFile = + std::max(entry.anyObjectFile, highestAvailablePriority); } - --priority; + --highestAvailablePriority; } } -// Sort sections by the profile data provided by __LLVM,__cg_profile sections. -// -// This first builds a call graph based on the profile data then merges sections -// according to the C³ heuristic. All clusters are then sorted by a density -// metric to further improve locality. -static DenseMap<const InputSection *, size_t> computeCallGraphProfileOrder() { - TimeTraceScope timeScope("Call graph profile sort"); - return CallGraphSort().run(); -} - -// Each section gets assigned the priority of the highest-priority symbol it -// contains. -DenseMap<const InputSection *, size_t> macho::buildInputSectionPriorities() { - if (config->callGraphProfileSort) - return computeCallGraphProfileOrder(); +DenseMap<const InputSection *, size_t> +macho::PriorityBuilder::buildInputSectionPriorities() { DenseMap<const InputSection *, size_t> sectionPriorities; + if (config->callGraphProfileSort) { + // Sort sections by the profile data provided by __LLVM,__cg_profile + // sections. + // + // This first builds a call graph based on the profile data then merges + // sections according to the C³ heuristic. All clusters are then sorted by a + // density metric to further improve locality. + TimeTraceScope timeScope("Call graph profile sort"); + sectionPriorities = CallGraphSort(callGraphProfile).run(); + } - if (config->priorities.empty()) + if (priorities.empty()) return sectionPriorities; - auto addSym = [&](Defined &sym) { - if (sym.isAbsolute()) + auto addSym = [&](const Defined *sym) { + Optional<size_t> symbolPriority = getSymbolPriority(sym); + if (!symbolPriority) return; - - auto it = config->priorities.find(sym.getName()); - if (it == config->priorities.end()) - return; - - SymbolPriorityEntry &entry = it->second; - size_t &priority = sectionPriorities[sym.isec]; - priority = - std::max(priority, getSymbolPriority(entry, sym.isec->getFile())); + size_t &priority = sectionPriorities[sym->isec]; + priority = std::max(priority, symbolPriority.getValue()); }; // TODO: Make sure this handles weak symbols correctly. @@ -372,7 +378,7 @@ DenseMap<const InputSection *, size_t> macho::buildInputSectionPriorities() { if (isa<ObjFile>(file)) for (Symbol *sym : file->symbols) if (auto *d = dyn_cast_or_null<Defined>(sym)) - addSym(*d); + addSym(d); } return sectionPriorities; |