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> §ionToIdx) { 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> §ionToIdx) { 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