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