//===- BPSectionOrderer.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "BPSectionOrderer.h" #include "InputSection.h" #include "Relocations.h" #include "Symbols.h" #include "lld/Common/BPSectionOrdererBase.inc" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StableHashing.h" #include "llvm/Support/Endian.h" #include "llvm/Support/xxhash.h" #define DEBUG_TYPE "bp-section-orderer" using namespace llvm; using namespace lld::macho; namespace { struct BPOrdererMachO; } template <> struct lld::BPOrdererTraits { using Section = macho::InputSection; using Symbol = macho::Symbol; }; namespace { struct BPOrdererMachO : lld::BPOrderer { static uint64_t getSize(const Section &sec) { return sec.getSize(); } static bool isCodeSection(const Section &sec) { return macho::isCodeSection(&sec); } static SmallVector getSymbols(const Section &sec) { SmallVector symbols; for (auto *sym : sec.symbols) if (auto *d = llvm::dyn_cast_or_null(sym)) symbols.emplace_back(d); return symbols; } // Linkage names can be prefixed with "_" or "l_" on Mach-O. See // Mangler::getNameWithPrefix() for details. std::optional static getResolvedLinkageName(llvm::StringRef name) { if (name.consume_front("_") || name.consume_front("l_")) return name; return {}; } static void getSectionHashes(const Section &sec, llvm::SmallVectorImpl &hashes, const llvm::DenseMap §ionToIdx) { constexpr unsigned windowSize = 4; // Calculate content hashes: k-mers and the last k-1 bytes. ArrayRef data = sec.data; if (data.size() >= windowSize) for (size_t i = 0; i <= data.size() - windowSize; ++i) hashes.push_back(llvm::support::endian::read32le(data.data() + i)); for (uint8_t byte : data.take_back(windowSize - 1)) hashes.push_back(byte); // Calculate relocation hashes for (const auto &r : sec.relocs) { if (r.length == 0 || r.referent.isNull() || r.offset >= data.size()) continue; uint64_t relocHash = getRelocHash(r, sectionToIdx); uint32_t start = (r.offset < windowSize) ? 0 : r.offset - windowSize + 1; for (uint32_t i = start; i < r.offset + r.length; i++) { auto window = data.drop_front(i).take_front(windowSize); hashes.push_back(xxh3_64bits(window) ^ relocHash); } } llvm::sort(hashes); hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end()); } static llvm::StringRef getSymName(const Symbol &sym) { return sym.getName(); } static uint64_t getSymValue(const Symbol &sym) { if (auto *d = dyn_cast(&sym)) return d->value; return 0; } static uint64_t getSymSize(const Symbol &sym) { if (auto *d = dyn_cast(&sym)) return d->size; return 0; } private: static uint64_t getRelocHash(const Reloc &reloc, const llvm::DenseMap §ionToIdx) { auto *isec = reloc.getReferentInputSection(); std::optional sectionIdx; if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end()) sectionIdx = it->second; uint64_t kind = -1, value = 0; if (isec) kind = uint64_t(isec->kind()); if (auto *sym = reloc.referent.dyn_cast()) { kind = (kind << 8) | uint8_t(sym->kind()); if (auto *d = llvm::dyn_cast(sym)) value = d->value; } return llvm::stable_hash_combine(kind, sectionIdx.value_or(0), value, reloc.addend); } }; } // namespace DenseMap lld::macho::runBalancedPartitioning( StringRef profilePath, bool forFunctionCompression, bool forDataCompression, bool compressionSortStartupFunctions, bool verbose) { // Collect candidate sections and associated symbols. SmallVector sections; DenseMap> rootSymbolToSectionIdxs; for (const auto *file : inputFiles) { for (auto *sec : file->sections) { for (auto &subsec : sec->subsections) { auto *isec = subsec.isec; if (!isec || isec->data.empty()) continue; size_t idx = sections.size(); sections.emplace_back(isec); for (auto *sym : BPOrdererMachO::getSymbols(*isec)) { auto rootName = getRootSymbol(sym->getName()); rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx); if (auto linkageName = BPOrdererMachO::getResolvedLinkageName(rootName)) rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert( idx); } } } } return BPOrdererMachO::computeOrder(profilePath, forFunctionCompression, forDataCompression, compressionSortStartupFunctions, verbose, sections, rootSymbolToSectionIdxs); }