[lld] f858fba - [lld][Macho][NFC] Encapsulate priorities map in a priority class
Roger Kim via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 23 10:57:37 PDT 2022
Author: Roger Kim
Date: 2022-03-23T13:57:26-04:00
New Revision: f858fba631d559c479d4728e3ea90098563f649e
URL: https://github.com/llvm/llvm-project/commit/f858fba631d559c479d4728e3ea90098563f649e
DIFF: https://github.com/llvm/llvm-project/commit/f858fba631d559c479d4728e3ea90098563f649e.diff
LOG: [lld][Macho][NFC] Encapsulate priorities map in a priority class
`config->priorities` has been used to hold the intermediate state during the construction of the order in which sections should be laid out. This is not a good place to hold this state since the intermediate state is not a "configuration" for LLD. It should be encapsulated in a class for building a mapping from section to priority (which I created in this diff as the `PriorityBuilder` class).
The same thing is being done for `config->callGraphProfile`.
Reviewed By: #lld-macho, int3
Differential Revision: https://reviews.llvm.org/D122156
Added:
Modified:
lld/MachO/Config.h
lld/MachO/Driver.cpp
lld/MachO/SectionPriorities.cpp
lld/MachO/SectionPriorities.h
lld/MachO/Writer.cpp
Removed:
################################################################################
diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index 865bb826b39de..ca81e2676a8e6 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -170,10 +170,6 @@ struct Configuration {
std::vector<SectionAlign> sectionAlignments;
std::vector<SegmentProtection> segmentProtections;
- llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities;
- llvm::MapVector<std::pair<const InputSection *, const InputSection *>,
- uint64_t>
- callGraphProfile;
bool callGraphProfileSort = false;
llvm::StringRef printSymbolOrder;
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index af62cfe572e1c..e7996f8f2520d 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -1453,7 +1453,7 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
StringRef orderFile = args.getLastArgValue(OPT_order_file);
if (!orderFile.empty())
- parseOrderFile(orderFile);
+ priorityBuilder.parseOrderFile(orderFile);
referenceStubBinder();
@@ -1510,7 +1510,7 @@ bool macho::link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
gatherInputSections();
if (config->callGraphProfileSort)
- extractCallGraphProfile();
+ priorityBuilder.extractCallGraphProfile();
if (config->deadStrip)
markLive();
diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp
index 405cb23c42c53..01a8f91160227 100644
--- a/lld/MachO/SectionPriorities.cpp
+++ b/lld/MachO/SectionPriorities.cpp
@@ -34,9 +34,11 @@ using namespace llvm::sys;
using namespace lld;
using namespace lld::macho;
+PriorityBuilder macho::priorityBuilder;
+
namespace {
-size_t lowestPriority = std::numeric_limits<size_t>::max();
+size_t highestAvailablePriority = std::numeric_limits<size_t>::max();
struct Edge {
int from;
@@ -62,7 +64,7 @@ struct Cluster {
class CallGraphSort {
public:
- CallGraphSort();
+ CallGraphSort(const MapVector<SectionPair, uint64_t> &profile);
DenseMap<const InputSection *, size_t> run();
@@ -75,13 +77,9 @@ class CallGraphSort {
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 {
@@ -94,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;
@@ -212,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 = lowestPriority;
+ int curOrder = highestAvailablePriority;
for (int leader : sorted) {
for (int i = leader;;) {
orderMap[sections[i]] = curOrder--;
@@ -251,12 +249,12 @@ DenseMap<const InputSection *, size_t> CallGraphSort::run() {
return orderMap;
}
-static Optional<size_t> getSymbolPriority(const Defined *sym) {
+Optional<size_t> macho::PriorityBuilder::getSymbolPriority(const Defined *sym) {
if (sym->isAbsolute())
return None;
- auto it = config->priorities.find(sym->getName());
- if (it == config->priorities.end())
+ auto it = priorities.find(sym->getName());
+ if (it == priorities.end())
return None;
const SymbolPriorityEntry &entry = it->second;
const InputFile *f = sym->isec->getFile();
@@ -273,9 +271,9 @@ static Optional<size_t> getSymbolPriority(const Defined *sym) {
return std::max(entry.objectFiles.lookup(filename), entry.anyObjectFile);
}
-void macho::extractCallGraphProfile() {
+void macho::PriorityBuilder::extractCallGraphProfile() {
TimeTraceScope timeScope("Extract call graph profile");
- bool hasOrderFile = !config->priorities.empty();
+ bool hasOrderFile = !priorities.empty();
for (const InputFile *file : inputFiles) {
auto *obj = dyn_cast_or_null<ObjFile>(file);
if (!obj)
@@ -289,13 +287,13 @@ void macho::extractCallGraphProfile() {
(hasOrderFile &&
(getSymbolPriority(fromSym) || getSymbolPriority(toSym))))
continue;
- config->callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count;
+ callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count;
}
}
}
-void macho::parseOrderFile(StringRef path) {
- assert(config->callGraphProfile.empty() &&
+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) {
@@ -304,7 +302,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
@@ -339,34 +336,34 @@ 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;
}
- lowestPriority = priority;
-}
-
-// 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();
}
-DenseMap<const InputSection *, size_t> macho::buildInputSectionPriorities() {
+DenseMap<const InputSection *, size_t>
+macho::PriorityBuilder::buildInputSectionPriorities() {
DenseMap<const InputSection *, size_t> sectionPriorities;
- if (config->callGraphProfileSort)
- sectionPriorities = computeCallGraphProfileOrder();
+ 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 = [&](const Defined *sym) {
diff --git a/lld/MachO/SectionPriorities.h b/lld/MachO/SectionPriorities.h
index 1557cc4747d93..5275ed2a2f242 100644
--- a/lld/MachO/SectionPriorities.h
+++ b/lld/MachO/SectionPriorities.h
@@ -15,41 +15,53 @@
namespace lld {
namespace macho {
-// Reads every input section's call graph profile, and combines them into
-// config->callGraphProfile. If an order file is present, any edges where one
-// or both of the vertices are specified in the order file are discarded.
-void extractCallGraphProfile();
+using SectionPair = std::pair<const InputSection *, const InputSection *>;
-// Reads the order file at `path` into config->priorities.
-//
-// An order file has one entry per line, in the following format:
-//
-// <cpu>:<object file>:<symbol name>
-//
-// <cpu> and <object file> are optional. If not specified, then that entry
-// matches any symbol of that name. Parsing this format is not quite
-// straightforward because the symbol name itself can contain colons, so when
-// encountering a colon, we consider the preceding characters to decide if it
-// can be a valid CPU type or file path.
-//
-// If a symbol is matched by multiple entries, then it takes the lowest-ordered
-// entry (the one nearest to the front of the list.)
-//
-// The file can also have line comments that start with '#'.
-void parseOrderFile(StringRef path);
+class PriorityBuilder {
+public:
+ // Reads every input section's call graph profile, and combines them into
+ // callGraphProfile. If an order file is present, any edges where one or both
+ // of the vertices are specified in the order file are discarded.
+ void extractCallGraphProfile();
-// 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.
-//
-// If either an order file or a call graph profile are present, this is used
-// as the source of priorities. If both are present, the order file takes
-// precedence, but the call graph profile is still used for symbols that don't
-// appear in the order file. If neither is present, an empty map is returned.
-//
-// Each section gets assigned the priority of the highest-priority symbol it
-// contains.
-llvm::DenseMap<const InputSection *, size_t> buildInputSectionPriorities();
+ // Reads the order file at `path` into config->priorities.
+ //
+ // An order file has one entry per line, in the following format:
+ //
+ // <cpu>:<object file>:<symbol name>
+ //
+ // <cpu> and <object file> are optional. If not specified, then that entry
+ // matches any symbol of that name. Parsing this format is not quite
+ // straightforward because the symbol name itself can contain colons, so when
+ // encountering a colon, we consider the preceding characters to decide if it
+ // can be a valid CPU type or file path.
+ //
+ // If a symbol is matched by multiple entries, then it takes the
+ // lowest-ordered entry (the one nearest to the front of the list.)
+ //
+ // The file can also have line comments that start with '#'.
+ void parseOrderFile(StringRef path);
+
+ // 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.
+ //
+ // If either an order file or a call graph profile are present, this is used
+ // as the source of priorities. If both are present, the order file takes
+ // precedence, but the call graph profile is still used for symbols that don't
+ // appear in the order file. If neither is present, an empty map is returned.
+ //
+ // Each section gets assigned the priority of the highest-priority symbol it
+ // contains.
+ llvm::DenseMap<const InputSection *, size_t> buildInputSectionPriorities();
+
+private:
+ llvm::Optional<size_t> getSymbolPriority(const Defined *sym);
+ llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities;
+ llvm::MapVector<SectionPair, uint64_t> callGraphProfile;
+};
+
+extern PriorityBuilder priorityBuilder;
} // namespace macho
} // namespace lld
diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index b1e7d4ca06d71..957042a769506 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -860,7 +860,7 @@ static void sortSegmentsAndSections() {
sortOutputSegments();
DenseMap<const InputSection *, size_t> isecPriorities =
- buildInputSectionPriorities();
+ priorityBuilder.buildInputSectionPriorities();
uint32_t sectionIndex = 0;
for (OutputSegment *seg : outputSegments) {
More information about the llvm-commits
mailing list