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,7 +11,7 @@ #include "InputSection.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SetVector.h" namespace lld { namespace macho { @@ -43,12 +43,6 @@ // The file can also have line comments that start with '#'. void parseOrderFile(StringRef path); - // Constructs internal mapping of section to priority based on order file - // data. - // - // Should only be called after `parseOrderFile()`. - 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. @@ -62,29 +56,19 @@ // contains. llvm::DenseMap buildInputSectionPriorities(); + // Represents a symbol specification. + // First element holds a symbol name. + // The second element holds an object file name or an empty string if we want + // to specify all symbols of a given name. + using SymbolSpecification = std::pair; + using SymbolOrder = + llvm::SetVector, + std::set>; + 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); - - using SymbolObjectFile = std::pair; - using SymbolOrder = llvm::SmallVector; // 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,17 @@ return orderMap; } -Optional macho::PriorityBuilder::getSymbolPriority(const Defined *sym) { +// Returns how an order file would specify this file. +// ie, "(archive_name_base_name)object_file_base_name" +static StringRef getOrderFileName(const InputFile &file) { + if (file.archiveName.empty()) + return path::filename(file.getName()); + return saver().save(path::filename(file.archiveName) + "(" + + path::filename(file.getName()) + ")"); +} + +Optional getSymbolPriority(const SymbolPriorites &priorities, + const Defined *sym) { if (sym->isAbsolute()) return None; @@ -262,18 +287,29 @@ 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; - if (f->archiveName.empty()) - filename = path::filename(f->getName()); - else - filename = saver().save(path::filename(f->archiveName) + "(" + - path::filename(f->getName()) + ")"); + StringRef filename = getOrderFileName(*f); 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, StringRef 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.str()); + 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 +320,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, getOrderFileName(*file), inputOrder) && + !isOrdered(*toSym, getOrderFileName(*file), inputOrder)))) callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count; } } @@ -335,12 +372,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 +393,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 +415,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];