xref: /llvm-project/lld/MachO/BPSectionOrderer.cpp (revision e0c7f081f1582d49f81ec4c6cdbf5d6ef13c58ba)
179e859e0SMax //===- BPSectionOrderer.cpp -----------------------------------------------===//
2e3b30bc5SEllis Hoag //
3e3b30bc5SEllis Hoag // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e3b30bc5SEllis Hoag // See https://llvm.org/LICENSE.txt for license information.
5e3b30bc5SEllis Hoag // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e3b30bc5SEllis Hoag //
7e3b30bc5SEllis Hoag //===----------------------------------------------------------------------===//
8e3b30bc5SEllis Hoag 
9e3b30bc5SEllis Hoag #include "BPSectionOrderer.h"
10e3b30bc5SEllis Hoag #include "InputSection.h"
11*e0c7f081SFangrui Song #include "Relocations.h"
12*e0c7f081SFangrui Song #include "Symbols.h"
13*e0c7f081SFangrui Song #include "lld/Common/BPSectionOrdererBase.inc"
14e3b30bc5SEllis Hoag #include "llvm/ADT/DenseMap.h"
15*e0c7f081SFangrui Song #include "llvm/ADT/StableHashing.h"
16*e0c7f081SFangrui Song #include "llvm/Support/Endian.h"
17*e0c7f081SFangrui Song #include "llvm/Support/xxhash.h"
18e3b30bc5SEllis Hoag 
19e3b30bc5SEllis Hoag #define DEBUG_TYPE "bp-section-orderer"
2079e859e0SMax 
21e3b30bc5SEllis Hoag using namespace llvm;
22e3b30bc5SEllis Hoag using namespace lld::macho;
23e3b30bc5SEllis Hoag 
24*e0c7f081SFangrui Song namespace {
25*e0c7f081SFangrui Song struct BPOrdererMachO;
26*e0c7f081SFangrui Song }
27*e0c7f081SFangrui Song template <> struct lld::BPOrdererTraits<struct BPOrdererMachO> {
28*e0c7f081SFangrui Song   using Section = macho::InputSection;
29*e0c7f081SFangrui Song   using Symbol = macho::Symbol;
30*e0c7f081SFangrui Song };
31*e0c7f081SFangrui Song namespace {
32*e0c7f081SFangrui Song struct BPOrdererMachO : lld::BPOrderer<BPOrdererMachO> {
33*e0c7f081SFangrui Song   static uint64_t getSize(const Section &sec) { return sec.getSize(); }
34*e0c7f081SFangrui Song   static bool isCodeSection(const Section &sec) {
35*e0c7f081SFangrui Song     return macho::isCodeSection(&sec);
36*e0c7f081SFangrui Song   }
37*e0c7f081SFangrui Song   static SmallVector<Symbol *, 0> getSymbols(const Section &sec) {
38*e0c7f081SFangrui Song     SmallVector<Symbol *, 0> symbols;
39*e0c7f081SFangrui Song     for (auto *sym : sec.symbols)
40*e0c7f081SFangrui Song       if (auto *d = llvm::dyn_cast_or_null<Defined>(sym))
41*e0c7f081SFangrui Song         symbols.emplace_back(d);
42*e0c7f081SFangrui Song     return symbols;
43*e0c7f081SFangrui Song   }
44*e0c7f081SFangrui Song 
45*e0c7f081SFangrui Song   // Linkage names can be prefixed with "_" or "l_" on Mach-O. See
46*e0c7f081SFangrui Song   // Mangler::getNameWithPrefix() for details.
47*e0c7f081SFangrui Song   std::optional<StringRef> static getResolvedLinkageName(llvm::StringRef name) {
48*e0c7f081SFangrui Song     if (name.consume_front("_") || name.consume_front("l_"))
49*e0c7f081SFangrui Song       return name;
50*e0c7f081SFangrui Song     return {};
51*e0c7f081SFangrui Song   }
52*e0c7f081SFangrui Song 
53*e0c7f081SFangrui Song   static void
54*e0c7f081SFangrui Song   getSectionHashes(const Section &sec, llvm::SmallVectorImpl<uint64_t> &hashes,
55*e0c7f081SFangrui Song                    const llvm::DenseMap<const void *, uint64_t> &sectionToIdx) {
56*e0c7f081SFangrui Song     constexpr unsigned windowSize = 4;
57*e0c7f081SFangrui Song 
58*e0c7f081SFangrui Song     // Calculate content hashes: k-mers and the last k-1 bytes.
59*e0c7f081SFangrui Song     ArrayRef<uint8_t> data = sec.data;
60*e0c7f081SFangrui Song     if (data.size() >= windowSize)
61*e0c7f081SFangrui Song       for (size_t i = 0; i <= data.size() - windowSize; ++i)
62*e0c7f081SFangrui Song         hashes.push_back(llvm::support::endian::read32le(data.data() + i));
63*e0c7f081SFangrui Song     for (uint8_t byte : data.take_back(windowSize - 1))
64*e0c7f081SFangrui Song       hashes.push_back(byte);
65*e0c7f081SFangrui Song 
66*e0c7f081SFangrui Song     // Calculate relocation hashes
67*e0c7f081SFangrui Song     for (const auto &r : sec.relocs) {
68*e0c7f081SFangrui Song       if (r.length == 0 || r.referent.isNull() || r.offset >= data.size())
69*e0c7f081SFangrui Song         continue;
70*e0c7f081SFangrui Song 
71*e0c7f081SFangrui Song       uint64_t relocHash = getRelocHash(r, sectionToIdx);
72*e0c7f081SFangrui Song       uint32_t start = (r.offset < windowSize) ? 0 : r.offset - windowSize + 1;
73*e0c7f081SFangrui Song       for (uint32_t i = start; i < r.offset + r.length; i++) {
74*e0c7f081SFangrui Song         auto window = data.drop_front(i).take_front(windowSize);
75*e0c7f081SFangrui Song         hashes.push_back(xxh3_64bits(window) ^ relocHash);
76*e0c7f081SFangrui Song       }
77*e0c7f081SFangrui Song     }
78*e0c7f081SFangrui Song 
79*e0c7f081SFangrui Song     llvm::sort(hashes);
80*e0c7f081SFangrui Song     hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end());
81*e0c7f081SFangrui Song   }
82*e0c7f081SFangrui Song 
83*e0c7f081SFangrui Song   static llvm::StringRef getSymName(const Symbol &sym) { return sym.getName(); }
84*e0c7f081SFangrui Song   static uint64_t getSymValue(const Symbol &sym) {
85*e0c7f081SFangrui Song     if (auto *d = dyn_cast<Defined>(&sym))
86*e0c7f081SFangrui Song       return d->value;
87*e0c7f081SFangrui Song     return 0;
88*e0c7f081SFangrui Song   }
89*e0c7f081SFangrui Song   static uint64_t getSymSize(const Symbol &sym) {
90*e0c7f081SFangrui Song     if (auto *d = dyn_cast<Defined>(&sym))
91*e0c7f081SFangrui Song       return d->size;
92*e0c7f081SFangrui Song     return 0;
93*e0c7f081SFangrui Song   }
94*e0c7f081SFangrui Song 
95*e0c7f081SFangrui Song private:
96*e0c7f081SFangrui Song   static uint64_t
97*e0c7f081SFangrui Song   getRelocHash(const Reloc &reloc,
98*e0c7f081SFangrui Song                const llvm::DenseMap<const void *, uint64_t> &sectionToIdx) {
99*e0c7f081SFangrui Song     auto *isec = reloc.getReferentInputSection();
100*e0c7f081SFangrui Song     std::optional<uint64_t> sectionIdx;
101*e0c7f081SFangrui Song     if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end())
102*e0c7f081SFangrui Song       sectionIdx = it->second;
103*e0c7f081SFangrui Song     uint64_t kind = -1, value = 0;
104*e0c7f081SFangrui Song     if (isec)
105*e0c7f081SFangrui Song       kind = uint64_t(isec->kind());
106*e0c7f081SFangrui Song 
107*e0c7f081SFangrui Song     if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) {
108*e0c7f081SFangrui Song       kind = (kind << 8) | uint8_t(sym->kind());
109*e0c7f081SFangrui Song       if (auto *d = llvm::dyn_cast<Defined>(sym))
110*e0c7f081SFangrui Song         value = d->value;
111*e0c7f081SFangrui Song     }
112*e0c7f081SFangrui Song     return llvm::stable_hash_combine(kind, sectionIdx.value_or(0), value,
113*e0c7f081SFangrui Song                                      reloc.addend);
114*e0c7f081SFangrui Song   }
115*e0c7f081SFangrui Song };
116*e0c7f081SFangrui Song } // namespace
117*e0c7f081SFangrui Song 
118cc88a5e6SFangrui Song DenseMap<const InputSection *, int> lld::macho::runBalancedPartitioning(
119cc88a5e6SFangrui Song     StringRef profilePath, bool forFunctionCompression, bool forDataCompression,
120ce91e215SEllis Hoag     bool compressionSortStartupFunctions, bool verbose) {
121*e0c7f081SFangrui Song   // Collect candidate sections and associated symbols.
122*e0c7f081SFangrui Song   SmallVector<InputSection *> sections;
123*e0c7f081SFangrui Song   DenseMap<CachedHashStringRef, DenseSet<unsigned>> rootSymbolToSectionIdxs;
124e3b30bc5SEllis Hoag   for (const auto *file : inputFiles) {
125e3b30bc5SEllis Hoag     for (auto *sec : file->sections) {
126e3b30bc5SEllis Hoag       for (auto &subsec : sec->subsections) {
127e3b30bc5SEllis Hoag         auto *isec = subsec.isec;
128*e0c7f081SFangrui Song         if (!isec || isec->data.empty())
129e3b30bc5SEllis Hoag           continue;
130*e0c7f081SFangrui Song         size_t idx = sections.size();
131*e0c7f081SFangrui Song         sections.emplace_back(isec);
132*e0c7f081SFangrui Song         for (auto *sym : BPOrdererMachO::getSymbols(*isec)) {
133*e0c7f081SFangrui Song           auto rootName = getRootSymbol(sym->getName());
134*e0c7f081SFangrui Song           rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx);
135*e0c7f081SFangrui Song           if (auto linkageName =
136*e0c7f081SFangrui Song                   BPOrdererMachO::getResolvedLinkageName(rootName))
137*e0c7f081SFangrui Song             rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert(
138*e0c7f081SFangrui Song                 idx);
139*e0c7f081SFangrui Song         }
140e3b30bc5SEllis Hoag       }
141e3b30bc5SEllis Hoag     }
142e3b30bc5SEllis Hoag   }
143e3b30bc5SEllis Hoag 
144*e0c7f081SFangrui Song   return BPOrdererMachO::computeOrder(profilePath, forFunctionCompression,
145*e0c7f081SFangrui Song                                       forDataCompression,
146*e0c7f081SFangrui Song                                       compressionSortStartupFunctions, verbose,
147*e0c7f081SFangrui Song                                       sections, rootSymbolToSectionIdxs);
148e3b30bc5SEllis Hoag }
149