diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1454,7 +1454,6 @@ StringRef orderFile = args.getLastArgValue(OPT_order_file); if (!orderFile.empty()) { priorityBuilder.parseOrderFile(orderFile); - priorityBuilder.populatePriorities(); } referenceStubBinder(); diff --git a/lld/MachO/SectionPriorities.h b/lld/MachO/SectionPriorities.h --- a/lld/MachO/SectionPriorities.h +++ b/lld/MachO/SectionPriorities.h @@ -11,6 +11,7 @@ #include "InputSection.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" namespace lld { namespace macho { @@ -42,8 +43,6 @@ // The file can also have line comments that start with '#'. void parseOrderFile(StringRef path); - void populatePriorities(); - // Returns layout priorities for some or all input sections. Sections are laid // out in decreasing order; that is, a higher priority section will be closer // to the beginning of its output section. @@ -57,30 +56,15 @@ // contains. llvm::DenseMap buildInputSectionPriorities(); -private: - // The symbol with the highest priority should be ordered first in the output - // section (modulo input section contiguity constraints). Using priority - // (highest first) instead of order (lowest first) has the convenient property - // that the default-constructed zero priority -- for symbols/sections without - // a user-defined order -- naturally ends up putting them at the end of the - // output. - struct SymbolPriorityEntry { - // The priority given to a matching symbol, regardless of which object file - // it originated from. - size_t anyObjectFile = 0; - // The priority given to a matching symbol from a particular object file. - llvm::DenseMap objectFiles; - }; - - llvm::Optional getSymbolPriority(const Defined *sym); - bool isOrdered(const Defined *sym); - using SymbolObjectFile = std::pair; - using SymbolOrder = std::vector; + using SymbolOrder = + llvm::SetVector, + std::set>; + +private: // This will be populated with symbols ordered so that the earlier // symbols will have higher priority than the later symbols. SymbolOrder inputOrder; - llvm::DenseMap priorities; llvm::MapVector callGraphProfile; }; diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp --- a/lld/MachO/SectionPriorities.cpp +++ b/lld/MachO/SectionPriorities.cpp @@ -37,9 +37,24 @@ PriorityBuilder macho::priorityBuilder; namespace { - +struct SymbolPriorityEntry; +using SymbolPriorites = llvm::DenseMap; size_t highestAvailablePriority = std::numeric_limits::max(); +// The symbol with the highest priority should be ordered first in the output +// section (modulo input section contiguity constraints). Using priority +// (highest first) instead of order (lowest first) has the convenient property +// that the default-constructed zero priority -- for symbols/sections without +// a user-defined order -- naturally ends up putting them at the end of the +// output. +struct SymbolPriorityEntry { + // The priority given to a matching symbol, regardless of which object file + // it originated from. + size_t anyObjectFile = 0; + // The priority given to a matching symbol from a particular object file. + llvm::DenseMap objectFiles; +}; + struct Edge { int from; uint64_t weight; @@ -249,7 +264,8 @@ return orderMap; } -Optional macho::PriorityBuilder::getSymbolPriority(const Defined *sym) { +Optional getSymbolPriority(const SymbolPriorites &priorities, + const Defined *sym) { if (sym->isAbsolute()) return None; @@ -271,9 +287,25 @@ return std::max(entry.objectFiles.lookup(filename), entry.anyObjectFile); } +// Return true iff symbolOrder contains `symbol` with the provided `objectFile` +// or with no object file. +bool isOrdered(const Defined &symbol, std::string objectFile, + const PriorityBuilder::SymbolOrder &symbolOrder) { + if (symbol.isAbsolute()) + return true; + + auto symbolWithoutFile = std::make_pair(symbol.getName().str(), ""); + if (symbolOrder.contains(symbolWithoutFile)) { + return true; + } + + auto symbolWithFile = std::make_pair(symbol.getName().str(), objectFile); + return symbolOrder.contains(symbolWithFile); +} + void macho::PriorityBuilder::extractCallGraphProfile() { TimeTraceScope timeScope("Extract call graph profile"); - bool hasOrderFile = !priorities.empty(); + bool hasInputOrder = !inputOrder.empty(); for (const InputFile *file : inputFiles) { auto *obj = dyn_cast_or_null(file); if (!obj) @@ -284,8 +316,9 @@ auto *fromSym = dyn_cast_or_null(obj->symbols[entry.fromIndex]); auto *toSym = dyn_cast_or_null(obj->symbols[entry.toIndex]); if (fromSym && toSym && - (!hasOrderFile || - (!getSymbolPriority(fromSym) && !getSymbolPriority(toSym)))) + (!hasInputOrder || + (!isOrdered(*fromSym, obj->getName().str(), inputOrder) && + !isOrdered(*toSym, obj->getName().str(), inputOrder)))) callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count; } } @@ -335,12 +368,14 @@ symbol = line.trim(); if (!symbol.empty()) { - inputOrder.push_back(std::make_pair(symbol.str(), objectFile.str())); + inputOrder.insert(std::make_pair(symbol.str(), objectFile.str())); } } } -void macho::PriorityBuilder::populatePriorities() { +static SymbolPriorites +populatePriorities(const PriorityBuilder::SymbolOrder &inputOrder) { + SymbolPriorites priorities; for (const auto &symbolObjectFile : inputOrder) { StringRef symbol = symbolObjectFile.first; StringRef objectFile = symbolObjectFile.second; @@ -354,10 +389,12 @@ --highestAvailablePriority; } + return priorities; } DenseMap macho::PriorityBuilder::buildInputSectionPriorities() { + SymbolPriorites priorities = populatePriorities(inputOrder); DenseMap sectionPriorities; if (config->callGraphProfileSort) { // Sort sections by the profile data provided by __LLVM,__cg_profile @@ -374,7 +411,7 @@ return sectionPriorities; auto addSym = [&](const Defined *sym) { - Optional symbolPriority = getSymbolPriority(sym); + Optional symbolPriority = getSymbolPriority(priorities, sym); if (!symbolPriority.hasValue()) return; size_t &priority = sectionPriorities[sym->isec];