1f23d57a6SLeonard Grey //===- SectionPriorities.cpp ----------------------------------------------===//
2f23d57a6SLeonard Grey //
3f23d57a6SLeonard Grey // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f23d57a6SLeonard Grey // See https://llvm.org/LICENSE.txt for license information.
5f23d57a6SLeonard Grey // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f23d57a6SLeonard Grey //
7f23d57a6SLeonard Grey //===----------------------------------------------------------------------===//
8f23d57a6SLeonard Grey ///
9f23d57a6SLeonard Grey /// This is based on the ELF port, see ELF/CallGraphSort.cpp for the details
10f23d57a6SLeonard Grey /// about the algorithm.
11f23d57a6SLeonard Grey ///
12f23d57a6SLeonard Grey //===----------------------------------------------------------------------===//
13f23d57a6SLeonard Grey 
14f23d57a6SLeonard Grey #include "SectionPriorities.h"
15f23d57a6SLeonard Grey #include "Config.h"
16f23d57a6SLeonard Grey #include "InputFiles.h"
17f23d57a6SLeonard Grey #include "Symbols.h"
18f23d57a6SLeonard Grey #include "Target.h"
19a52b9102SLeonard Grey 
20a5c9d717SLeonard Grey #include "lld/Common/Args.h"
21a5c9d717SLeonard Grey #include "lld/Common/CommonLinkerContext.h"
22f23d57a6SLeonard Grey #include "lld/Common/ErrorHandler.h"
23f23d57a6SLeonard Grey #include "llvm/ADT/DenseMap.h"
24f23d57a6SLeonard Grey #include "llvm/ADT/MapVector.h"
25a5c9d717SLeonard Grey #include "llvm/ADT/Optional.h"
26a5c9d717SLeonard Grey #include "llvm/Support/Path.h"
27f23d57a6SLeonard Grey #include "llvm/Support/TimeProfiler.h"
28f23d57a6SLeonard Grey #include "llvm/Support/raw_ostream.h"
29f23d57a6SLeonard Grey #include <numeric>
30f23d57a6SLeonard Grey 
31f23d57a6SLeonard Grey using namespace llvm;
32a5c9d717SLeonard Grey using namespace llvm::MachO;
33a5c9d717SLeonard Grey using namespace llvm::sys;
34f23d57a6SLeonard Grey using namespace lld;
35f23d57a6SLeonard Grey using namespace lld::macho;
36f23d57a6SLeonard Grey 
37f858fba6SRoger Kim PriorityBuilder macho::priorityBuilder;
38f858fba6SRoger Kim 
39f23d57a6SLeonard Grey namespace {
40a52b9102SLeonard Grey 
41f858fba6SRoger Kim size_t highestAvailablePriority = std::numeric_limits<size_t>::max();
42a52b9102SLeonard Grey 
43f23d57a6SLeonard Grey struct Edge {
44f23d57a6SLeonard Grey   int from;
45f23d57a6SLeonard Grey   uint64_t weight;
46f23d57a6SLeonard Grey };
47f23d57a6SLeonard Grey 
48f23d57a6SLeonard Grey struct Cluster {
Cluster__anon524c8ef10111::Cluster49f23d57a6SLeonard Grey   Cluster(int sec, size_t s) : next(sec), prev(sec), size(s) {}
50f23d57a6SLeonard Grey 
getDensity__anon524c8ef10111::Cluster51f23d57a6SLeonard Grey   double getDensity() const {
52f23d57a6SLeonard Grey     if (size == 0)
53f23d57a6SLeonard Grey       return 0;
54f23d57a6SLeonard Grey     return double(weight) / double(size);
55f23d57a6SLeonard Grey   }
56f23d57a6SLeonard Grey 
57f23d57a6SLeonard Grey   int next;
58f23d57a6SLeonard Grey   int prev;
59f23d57a6SLeonard Grey   uint64_t size;
60f23d57a6SLeonard Grey   uint64_t weight = 0;
61f23d57a6SLeonard Grey   uint64_t initialWeight = 0;
62f23d57a6SLeonard Grey   Edge bestPred = {-1, 0};
63f23d57a6SLeonard Grey };
64f23d57a6SLeonard Grey 
65f23d57a6SLeonard Grey class CallGraphSort {
66f23d57a6SLeonard Grey public:
67f858fba6SRoger Kim   CallGraphSort(const MapVector<SectionPair, uint64_t> &profile);
68f23d57a6SLeonard Grey 
69f23d57a6SLeonard Grey   DenseMap<const InputSection *, size_t> run();
70f23d57a6SLeonard Grey 
71f23d57a6SLeonard Grey private:
72f23d57a6SLeonard Grey   std::vector<Cluster> clusters;
73f23d57a6SLeonard Grey   std::vector<const InputSection *> sections;
74f23d57a6SLeonard Grey };
75f23d57a6SLeonard Grey // Maximum amount the combined cluster density can be worse than the original
76f23d57a6SLeonard Grey // cluster to consider merging.
77f23d57a6SLeonard Grey constexpr int MAX_DENSITY_DEGRADATION = 8;
78f23d57a6SLeonard Grey } // end anonymous namespace
79f23d57a6SLeonard Grey 
80f858fba6SRoger Kim // Take the edge list in callGraphProfile, resolve symbol names to Symbols, and
81f858fba6SRoger Kim // generate a graph between InputSections with the provided weights.
CallGraphSort(const MapVector<SectionPair,uint64_t> & profile)82f858fba6SRoger Kim CallGraphSort::CallGraphSort(const MapVector<SectionPair, uint64_t> &profile) {
83f23d57a6SLeonard Grey   DenseMap<const InputSection *, int> secToCluster;
84f23d57a6SLeonard Grey 
85f23d57a6SLeonard Grey   auto getOrCreateCluster = [&](const InputSection *isec) -> int {
86f23d57a6SLeonard Grey     auto res = secToCluster.try_emplace(isec, clusters.size());
87f23d57a6SLeonard Grey     if (res.second) {
88f23d57a6SLeonard Grey       sections.push_back(isec);
89f23d57a6SLeonard Grey       clusters.emplace_back(clusters.size(), isec->getSize());
90f23d57a6SLeonard Grey     }
91f23d57a6SLeonard Grey     return res.first->second;
92f23d57a6SLeonard Grey   };
93f23d57a6SLeonard Grey 
94f23d57a6SLeonard Grey   // Create the graph
95f858fba6SRoger Kim   for (const std::pair<SectionPair, uint64_t> &c : profile) {
96f23d57a6SLeonard Grey     const auto fromSec = c.first.first->canonical();
97f23d57a6SLeonard Grey     const auto toSec = c.first.second->canonical();
98f23d57a6SLeonard Grey     uint64_t weight = c.second;
99f23d57a6SLeonard Grey     // Ignore edges between input sections belonging to different output
100f23d57a6SLeonard Grey     // sections.  This is done because otherwise we would end up with clusters
101f23d57a6SLeonard Grey     // containing input sections that can't actually be placed adjacently in the
102f23d57a6SLeonard Grey     // output.  This messes with the cluster size and density calculations.  We
103f23d57a6SLeonard Grey     // would also end up moving input sections in other output sections without
104f23d57a6SLeonard Grey     // moving them closer to what calls them.
105f23d57a6SLeonard Grey     if (fromSec->parent != toSec->parent)
106f23d57a6SLeonard Grey       continue;
107f23d57a6SLeonard Grey 
108f23d57a6SLeonard Grey     int from = getOrCreateCluster(fromSec);
109f23d57a6SLeonard Grey     int to = getOrCreateCluster(toSec);
110f23d57a6SLeonard Grey 
111f23d57a6SLeonard Grey     clusters[to].weight += weight;
112f23d57a6SLeonard Grey 
113f23d57a6SLeonard Grey     if (from == to)
114f23d57a6SLeonard Grey       continue;
115f23d57a6SLeonard Grey 
116f23d57a6SLeonard Grey     // Remember the best edge.
117f23d57a6SLeonard Grey     Cluster &toC = clusters[to];
118f23d57a6SLeonard Grey     if (toC.bestPred.from == -1 || toC.bestPred.weight < weight) {
119f23d57a6SLeonard Grey       toC.bestPred.from = from;
120f23d57a6SLeonard Grey       toC.bestPred.weight = weight;
121f23d57a6SLeonard Grey     }
122f23d57a6SLeonard Grey   }
123f23d57a6SLeonard Grey   for (Cluster &c : clusters)
124f23d57a6SLeonard Grey     c.initialWeight = c.weight;
125f23d57a6SLeonard Grey }
126f23d57a6SLeonard Grey 
127f23d57a6SLeonard Grey // It's bad to merge clusters which would degrade the density too much.
isNewDensityBad(Cluster & a,Cluster & b)128f23d57a6SLeonard Grey static bool isNewDensityBad(Cluster &a, Cluster &b) {
129f23d57a6SLeonard Grey   double newDensity = double(a.weight + b.weight) / double(a.size + b.size);
130f23d57a6SLeonard Grey   return newDensity < a.getDensity() / MAX_DENSITY_DEGRADATION;
131f23d57a6SLeonard Grey }
132f23d57a6SLeonard Grey 
133f23d57a6SLeonard Grey // Find the leader of V's belonged cluster (represented as an equivalence
134f23d57a6SLeonard Grey // class). We apply union-find path-halving technique (simple to implement) in
135f23d57a6SLeonard Grey // the meantime as it decreases depths and the time complexity.
getLeader(std::vector<int> & leaders,int v)136f23d57a6SLeonard Grey static int getLeader(std::vector<int> &leaders, int v) {
137f23d57a6SLeonard Grey   while (leaders[v] != v) {
138f23d57a6SLeonard Grey     leaders[v] = leaders[leaders[v]];
139f23d57a6SLeonard Grey     v = leaders[v];
140f23d57a6SLeonard Grey   }
141f23d57a6SLeonard Grey   return v;
142f23d57a6SLeonard Grey }
143f23d57a6SLeonard Grey 
mergeClusters(std::vector<Cluster> & cs,Cluster & into,int intoIdx,Cluster & from,int fromIdx)144f23d57a6SLeonard Grey static void mergeClusters(std::vector<Cluster> &cs, Cluster &into, int intoIdx,
145f23d57a6SLeonard Grey                           Cluster &from, int fromIdx) {
146f23d57a6SLeonard Grey   int tail1 = into.prev, tail2 = from.prev;
147f23d57a6SLeonard Grey   into.prev = tail2;
148f23d57a6SLeonard Grey   cs[tail2].next = intoIdx;
149f23d57a6SLeonard Grey   from.prev = tail1;
150f23d57a6SLeonard Grey   cs[tail1].next = fromIdx;
151f23d57a6SLeonard Grey   into.size += from.size;
152f23d57a6SLeonard Grey   into.weight += from.weight;
153f23d57a6SLeonard Grey   from.size = 0;
154f23d57a6SLeonard Grey   from.weight = 0;
155f23d57a6SLeonard Grey }
156f23d57a6SLeonard Grey 
157f23d57a6SLeonard Grey // Group InputSections into clusters using the Call-Chain Clustering heuristic
158f23d57a6SLeonard Grey // then sort the clusters by density.
run()159f23d57a6SLeonard Grey DenseMap<const InputSection *, size_t> CallGraphSort::run() {
160f23d57a6SLeonard Grey   const uint64_t maxClusterSize = target->getPageSize();
161f23d57a6SLeonard Grey 
162f23d57a6SLeonard Grey   // Cluster indices sorted by density.
163f23d57a6SLeonard Grey   std::vector<int> sorted(clusters.size());
164f23d57a6SLeonard Grey   // For union-find.
165f23d57a6SLeonard Grey   std::vector<int> leaders(clusters.size());
166f23d57a6SLeonard Grey 
167f23d57a6SLeonard Grey   std::iota(leaders.begin(), leaders.end(), 0);
168f23d57a6SLeonard Grey   std::iota(sorted.begin(), sorted.end(), 0);
169f23d57a6SLeonard Grey 
170f23d57a6SLeonard Grey   llvm::stable_sort(sorted, [&](int a, int b) {
171f23d57a6SLeonard Grey     return clusters[a].getDensity() > clusters[b].getDensity();
172f23d57a6SLeonard Grey   });
173f23d57a6SLeonard Grey 
174f23d57a6SLeonard Grey   for (int l : sorted) {
175f23d57a6SLeonard Grey     // The cluster index is the same as the index of its leader here because
176f23d57a6SLeonard Grey     // clusters[L] has not been merged into another cluster yet.
177f23d57a6SLeonard Grey     Cluster &c = clusters[l];
178f23d57a6SLeonard Grey 
179f23d57a6SLeonard Grey     // Don't consider merging if the edge is unlikely.
180f23d57a6SLeonard Grey     if (c.bestPred.from == -1 || c.bestPred.weight * 10 <= c.initialWeight)
181f23d57a6SLeonard Grey       continue;
182f23d57a6SLeonard Grey 
183f23d57a6SLeonard Grey     int predL = getLeader(leaders, c.bestPred.from);
184f23d57a6SLeonard Grey     // Already in the same cluster.
185f23d57a6SLeonard Grey     if (l == predL)
186f23d57a6SLeonard Grey       continue;
187f23d57a6SLeonard Grey 
188f23d57a6SLeonard Grey     Cluster *predC = &clusters[predL];
189f23d57a6SLeonard Grey     if (c.size + predC->size > maxClusterSize)
190f23d57a6SLeonard Grey       continue;
191f23d57a6SLeonard Grey 
192f23d57a6SLeonard Grey     if (isNewDensityBad(*predC, c))
193f23d57a6SLeonard Grey       continue;
194f23d57a6SLeonard Grey 
195f23d57a6SLeonard Grey     leaders[l] = predL;
196f23d57a6SLeonard Grey     mergeClusters(clusters, *predC, predL, c, l);
197f23d57a6SLeonard Grey   }
198f23d57a6SLeonard Grey   // Sort remaining non-empty clusters by density.
199f23d57a6SLeonard Grey   sorted.clear();
200f23d57a6SLeonard Grey   for (int i = 0, e = (int)clusters.size(); i != e; ++i)
201f23d57a6SLeonard Grey     if (clusters[i].size > 0)
202f23d57a6SLeonard Grey       sorted.push_back(i);
203f23d57a6SLeonard Grey   llvm::stable_sort(sorted, [&](int a, int b) {
204f23d57a6SLeonard Grey     return clusters[a].getDensity() > clusters[b].getDensity();
205f23d57a6SLeonard Grey   });
206f23d57a6SLeonard Grey 
207f23d57a6SLeonard Grey   DenseMap<const InputSection *, size_t> orderMap;
208f23d57a6SLeonard Grey 
209f23d57a6SLeonard Grey   // Sections will be sorted by decreasing order. Absent sections will have
210f23d57a6SLeonard Grey   // priority 0 and be placed at the end of sections.
211f23d57a6SLeonard Grey   // NB: This is opposite from COFF/ELF to be compatible with the existing
212f23d57a6SLeonard Grey   // order-file code.
213f858fba6SRoger Kim   int curOrder = highestAvailablePriority;
214f23d57a6SLeonard Grey   for (int leader : sorted) {
215f23d57a6SLeonard Grey     for (int i = leader;;) {
216f23d57a6SLeonard Grey       orderMap[sections[i]] = curOrder--;
217f23d57a6SLeonard Grey       i = clusters[i].next;
218f23d57a6SLeonard Grey       if (i == leader)
219f23d57a6SLeonard Grey         break;
220f23d57a6SLeonard Grey     }
221f23d57a6SLeonard Grey   }
222f23d57a6SLeonard Grey   if (!config->printSymbolOrder.empty()) {
223f23d57a6SLeonard Grey     std::error_code ec;
224f23d57a6SLeonard Grey     raw_fd_ostream os(config->printSymbolOrder, ec, sys::fs::OF_None);
225f23d57a6SLeonard Grey     if (ec) {
226f23d57a6SLeonard Grey       error("cannot open " + config->printSymbolOrder + ": " + ec.message());
227f23d57a6SLeonard Grey       return orderMap;
228f23d57a6SLeonard Grey     }
229f23d57a6SLeonard Grey     // Print the symbols ordered by C3, in the order of decreasing curOrder
230f23d57a6SLeonard Grey     // Instead of sorting all the orderMap, just repeat the loops above.
231f23d57a6SLeonard Grey     for (int leader : sorted)
232f23d57a6SLeonard Grey       for (int i = leader;;) {
233f23d57a6SLeonard Grey         const InputSection *isec = sections[i];
234f23d57a6SLeonard Grey         // Search all the symbols in the file of the section
235f23d57a6SLeonard Grey         // and find out a Defined symbol with name that is within the
236f23d57a6SLeonard Grey         // section.
237f23d57a6SLeonard Grey         for (Symbol *sym : isec->getFile()->symbols) {
238f23d57a6SLeonard Grey           if (auto *d = dyn_cast_or_null<Defined>(sym)) {
239f23d57a6SLeonard Grey             if (d->isec == isec)
240f23d57a6SLeonard Grey               os << sym->getName() << "\n";
241f23d57a6SLeonard Grey           }
242f23d57a6SLeonard Grey         }
243f23d57a6SLeonard Grey         i = clusters[i].next;
244f23d57a6SLeonard Grey         if (i == leader)
245f23d57a6SLeonard Grey           break;
246f23d57a6SLeonard Grey       }
247f23d57a6SLeonard Grey   }
248f23d57a6SLeonard Grey 
249f23d57a6SLeonard Grey   return orderMap;
250f23d57a6SLeonard Grey }
251f23d57a6SLeonard Grey 
getSymbolPriority(const Defined * sym)252f858fba6SRoger Kim Optional<size_t> macho::PriorityBuilder::getSymbolPriority(const Defined *sym) {
253a52b9102SLeonard Grey   if (sym->isAbsolute())
254a52b9102SLeonard Grey     return None;
255a52b9102SLeonard Grey 
256f858fba6SRoger Kim   auto it = priorities.find(sym->getName());
257f858fba6SRoger Kim   if (it == priorities.end())
258a52b9102SLeonard Grey     return None;
259a52b9102SLeonard Grey   const SymbolPriorityEntry &entry = it->second;
260a52b9102SLeonard Grey   const InputFile *f = sym->isec->getFile();
261a52b9102SLeonard Grey   if (!f)
262a52b9102SLeonard Grey     return entry.anyObjectFile;
263a5c9d717SLeonard Grey   // We don't use toString(InputFile *) here because it returns the full path
264a5c9d717SLeonard Grey   // for object files, and we only want the basename.
265a5c9d717SLeonard Grey   StringRef filename;
266a5c9d717SLeonard Grey   if (f->archiveName.empty())
267a5c9d717SLeonard Grey     filename = path::filename(f->getName());
268a5c9d717SLeonard Grey   else
269a5c9d717SLeonard Grey     filename = saver().save(path::filename(f->archiveName) + "(" +
270a5c9d717SLeonard Grey                             path::filename(f->getName()) + ")");
271a5c9d717SLeonard Grey   return std::max(entry.objectFiles.lookup(filename), entry.anyObjectFile);
272a5c9d717SLeonard Grey }
273a5c9d717SLeonard Grey 
extractCallGraphProfile()274f858fba6SRoger Kim void macho::PriorityBuilder::extractCallGraphProfile() {
275a5c9d717SLeonard Grey   TimeTraceScope timeScope("Extract call graph profile");
276f858fba6SRoger Kim   bool hasOrderFile = !priorities.empty();
277a5c9d717SLeonard Grey   for (const InputFile *file : inputFiles) {
278a5c9d717SLeonard Grey     auto *obj = dyn_cast_or_null<ObjFile>(file);
279a5c9d717SLeonard Grey     if (!obj)
280a5c9d717SLeonard Grey       continue;
281a5c9d717SLeonard Grey     for (const CallGraphEntry &entry : obj->callGraph) {
282a5c9d717SLeonard Grey       assert(entry.fromIndex < obj->symbols.size() &&
283a5c9d717SLeonard Grey              entry.toIndex < obj->symbols.size());
284a5c9d717SLeonard Grey       auto *fromSym = dyn_cast_or_null<Defined>(obj->symbols[entry.fromIndex]);
285a5c9d717SLeonard Grey       auto *toSym = dyn_cast_or_null<Defined>(obj->symbols[entry.toIndex]);
28634b97295SRoger Kim       if (fromSym && toSym &&
28734b97295SRoger Kim           (!hasOrderFile ||
28834b97295SRoger Kim            (!getSymbolPriority(fromSym) && !getSymbolPriority(toSym))))
289f858fba6SRoger Kim         callGraphProfile[{fromSym->isec, toSym->isec}] += entry.count;
290a5c9d717SLeonard Grey     }
291a5c9d717SLeonard Grey   }
292a5c9d717SLeonard Grey }
293a5c9d717SLeonard Grey 
parseOrderFile(StringRef path)294f858fba6SRoger Kim void macho::PriorityBuilder::parseOrderFile(StringRef path) {
295f858fba6SRoger Kim   assert(callGraphProfile.empty() &&
296a52b9102SLeonard Grey          "Order file must be parsed before call graph profile is processed");
297a5c9d717SLeonard Grey   Optional<MemoryBufferRef> buffer = readFile(path);
298a5c9d717SLeonard Grey   if (!buffer) {
299a5c9d717SLeonard Grey     error("Could not read order file at " + path);
300a5c9d717SLeonard Grey     return;
301a5c9d717SLeonard Grey   }
302a5c9d717SLeonard Grey 
303a5c9d717SLeonard Grey   MemoryBufferRef mbref = *buffer;
304a5c9d717SLeonard Grey   for (StringRef line : args::getLines(mbref)) {
305a5c9d717SLeonard Grey     StringRef objectFile, symbol;
306a5c9d717SLeonard Grey     line = line.take_until([](char c) { return c == '#'; }); // ignore comments
307a5c9d717SLeonard Grey     line = line.ltrim();
308a5c9d717SLeonard Grey 
309a5c9d717SLeonard Grey     CPUType cpuType = StringSwitch<CPUType>(line)
310a5c9d717SLeonard Grey                           .StartsWith("i386:", CPU_TYPE_I386)
311a5c9d717SLeonard Grey                           .StartsWith("x86_64:", CPU_TYPE_X86_64)
312a5c9d717SLeonard Grey                           .StartsWith("arm:", CPU_TYPE_ARM)
313a5c9d717SLeonard Grey                           .StartsWith("arm64:", CPU_TYPE_ARM64)
314a5c9d717SLeonard Grey                           .StartsWith("ppc:", CPU_TYPE_POWERPC)
315a5c9d717SLeonard Grey                           .StartsWith("ppc64:", CPU_TYPE_POWERPC64)
316a5c9d717SLeonard Grey                           .Default(CPU_TYPE_ANY);
317a5c9d717SLeonard Grey 
318a5c9d717SLeonard Grey     if (cpuType != CPU_TYPE_ANY && cpuType != target->cpuType)
319a5c9d717SLeonard Grey       continue;
320a5c9d717SLeonard Grey 
321a5c9d717SLeonard Grey     // Drop the CPU type as well as the colon
322a5c9d717SLeonard Grey     if (cpuType != CPU_TYPE_ANY)
323a5c9d717SLeonard Grey       line = line.drop_until([](char c) { return c == ':'; }).drop_front();
324a5c9d717SLeonard Grey 
325a5c9d717SLeonard Grey     constexpr std::array<StringRef, 2> fileEnds = {".o:", ".o):"};
326a5c9d717SLeonard Grey     for (StringRef fileEnd : fileEnds) {
327a5c9d717SLeonard Grey       size_t pos = line.find(fileEnd);
328a5c9d717SLeonard Grey       if (pos != StringRef::npos) {
329a5c9d717SLeonard Grey         // Split the string around the colon
330a5c9d717SLeonard Grey         objectFile = line.take_front(pos + fileEnd.size() - 1);
331a5c9d717SLeonard Grey         line = line.drop_front(pos + fileEnd.size());
332a5c9d717SLeonard Grey         break;
333a5c9d717SLeonard Grey       }
334a5c9d717SLeonard Grey     }
335a5c9d717SLeonard Grey     symbol = line.trim();
336a5c9d717SLeonard Grey 
337a5c9d717SLeonard Grey     if (!symbol.empty()) {
338f858fba6SRoger Kim       SymbolPriorityEntry &entry = priorities[symbol];
339a5c9d717SLeonard Grey       if (!objectFile.empty())
340f858fba6SRoger Kim         entry.objectFiles.insert(
341f858fba6SRoger Kim             std::make_pair(objectFile, highestAvailablePriority));
342a5c9d717SLeonard Grey       else
343f858fba6SRoger Kim         entry.anyObjectFile =
344f858fba6SRoger Kim             std::max(entry.anyObjectFile, highestAvailablePriority);
345a5c9d717SLeonard Grey     }
346a5c9d717SLeonard Grey 
347f858fba6SRoger Kim     --highestAvailablePriority;
348a5c9d717SLeonard Grey   }
349a5c9d717SLeonard Grey }
350a5c9d717SLeonard Grey 
351f858fba6SRoger Kim DenseMap<const InputSection *, size_t>
buildInputSectionPriorities()352f858fba6SRoger Kim macho::PriorityBuilder::buildInputSectionPriorities() {
353a5c9d717SLeonard Grey   DenseMap<const InputSection *, size_t> sectionPriorities;
354f858fba6SRoger Kim   if (config->callGraphProfileSort) {
355f858fba6SRoger Kim     // Sort sections by the profile data provided by __LLVM,__cg_profile
356f858fba6SRoger Kim     // sections.
357f858fba6SRoger Kim     //
358f858fba6SRoger Kim     // This first builds a call graph based on the profile data then merges
359f858fba6SRoger Kim     // sections according to the C³ heuristic. All clusters are then sorted by a
360f858fba6SRoger Kim     // density metric to further improve locality.
361f858fba6SRoger Kim     TimeTraceScope timeScope("Call graph profile sort");
362f858fba6SRoger Kim     sectionPriorities = CallGraphSort(callGraphProfile).run();
363f858fba6SRoger Kim   }
364a5c9d717SLeonard Grey 
365f858fba6SRoger Kim   if (priorities.empty())
366a5c9d717SLeonard Grey     return sectionPriorities;
367a5c9d717SLeonard Grey 
368a52b9102SLeonard Grey   auto addSym = [&](const Defined *sym) {
369a52b9102SLeonard Grey     Optional<size_t> symbolPriority = getSymbolPriority(sym);
370586fb81eSKazu Hirata     if (!symbolPriority)
371a5c9d717SLeonard Grey       return;
372a52b9102SLeonard Grey     size_t &priority = sectionPriorities[sym->isec];
373*5cff5142SKazu Hirata     priority = std::max(priority, symbolPriority.value());
374a5c9d717SLeonard Grey   };
375a5c9d717SLeonard Grey 
376a5c9d717SLeonard Grey   // TODO: Make sure this handles weak symbols correctly.
377a5c9d717SLeonard Grey   for (const InputFile *file : inputFiles) {
378a5c9d717SLeonard Grey     if (isa<ObjFile>(file))
379a5c9d717SLeonard Grey       for (Symbol *sym : file->symbols)
380a5c9d717SLeonard Grey         if (auto *d = dyn_cast_or_null<Defined>(sym))
381a52b9102SLeonard Grey           addSym(d);
382a5c9d717SLeonard Grey   }
383a5c9d717SLeonard Grey 
384a5c9d717SLeonard Grey   return sectionPriorities;
385a5c9d717SLeonard Grey }
386