[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