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