diff options
Diffstat (limited to 'lld/MachO')
| -rw-r--r-- | lld/MachO/Arch/ARM64.cpp | 2 | ||||
| -rw-r--r-- | lld/MachO/BPSectionOrderer.cpp | 416 | ||||
| -rw-r--r-- | lld/MachO/BPSectionOrderer.h | 125 | ||||
| -rw-r--r-- | lld/MachO/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | lld/MachO/ConcatOutputSection.cpp | 4 | ||||
| -rw-r--r-- | lld/MachO/Config.h | 11 | ||||
| -rw-r--r-- | lld/MachO/Driver.cpp | 49 | ||||
| -rw-r--r-- | lld/MachO/DriverUtils.cpp | 14 | ||||
| -rw-r--r-- | lld/MachO/EhFrame.cpp | 2 | ||||
| -rw-r--r-- | lld/MachO/ICF.cpp | 24 | ||||
| -rw-r--r-- | lld/MachO/InputFiles.cpp | 6 | ||||
| -rw-r--r-- | lld/MachO/InputSection.cpp | 4 | ||||
| -rw-r--r-- | lld/MachO/MarkLive.cpp | 4 | ||||
| -rw-r--r-- | lld/MachO/ObjC.cpp | 10 | ||||
| -rw-r--r-- | lld/MachO/Options.td | 27 | ||||
| -rw-r--r-- | lld/MachO/Relocations.cpp | 4 | ||||
| -rw-r--r-- | lld/MachO/SectionPriorities.cpp | 14 | ||||
| -rw-r--r-- | lld/MachO/SymbolTable.cpp | 13 | ||||
| -rw-r--r-- | lld/MachO/SyntheticSections.cpp | 8 | ||||
| -rw-r--r-- | lld/MachO/UnwindInfoSection.cpp | 2 |
20 files changed, 262 insertions, 478 deletions
diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp index 882873ae5de0..bf458e392be8 100644 --- a/lld/MachO/Arch/ARM64.cpp +++ b/lld/MachO/Arch/ARM64.cpp @@ -202,7 +202,7 @@ InputSection *ARM64::getThunkBranchTarget(InputSection *thunk) const { assert(thunk->relocs.size() == 1 && "expected a single reloc on ARM64 ICF thunk"); auto &reloc = thunk->relocs[0]; - assert(reloc.referent.is<InputSection *>() && + assert(isa<InputSection *>(reloc.referent) && "ARM64 thunk reloc is expected to point to an InputSection"); return reloc.referent.dyn_cast<InputSection *>(); diff --git a/lld/MachO/BPSectionOrderer.cpp b/lld/MachO/BPSectionOrderer.cpp index 5db2242a35ef..0ffbf16007fd 100644 --- a/lld/MachO/BPSectionOrderer.cpp +++ b/lld/MachO/BPSectionOrderer.cpp @@ -1,4 +1,4 @@ -//===- BPSectionOrderer.cpp--------------------------------------*- C++ -*-===// +//===- 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. @@ -8,428 +8,42 @@ #include "BPSectionOrderer.h" #include "InputSection.h" -#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ProfileData/InstrProfReader.h" -#include "llvm/Support/BalancedPartitioning.h" -#include "llvm/Support/TimeProfiler.h" -#include "llvm/Support/VirtualFileSystem.h" -#include "llvm/Support/xxhash.h" #define DEBUG_TYPE "bp-section-orderer" + using namespace llvm; using namespace lld::macho; -using UtilityNodes = SmallVector<BPFunctionNode::UtilityNodeT>; - -/// Symbols can be appended with "(.__uniq.xxxx)?.llvm.yyyy" where "xxxx" and -/// "yyyy" are numbers that could change between builds. We need to use the root -/// symbol name before this suffix so these symbols can be matched with profiles -/// which may have different suffixes. -static StringRef getRootSymbol(StringRef Name) { - auto [P0, S0] = Name.rsplit(".llvm."); - auto [P1, S1] = P0.rsplit(".__uniq."); - return P1; -} - -static uint64_t getRelocHash(StringRef kind, uint64_t sectionIdx, - uint64_t offset, uint64_t addend) { - return xxHash64((kind + ": " + Twine::utohexstr(sectionIdx) + " + " + - Twine::utohexstr(offset) + " + " + Twine::utohexstr(addend)) - .str()); -} - -static uint64_t -getRelocHash(const Reloc &reloc, - const DenseMap<const InputSection *, uint64_t> §ionToIdx) { - auto *isec = reloc.getReferentInputSection(); - std::optional<uint64_t> sectionIdx; - auto sectionIdxIt = sectionToIdx.find(isec); - if (sectionIdxIt != sectionToIdx.end()) - sectionIdx = sectionIdxIt->getSecond(); - std::string kind; - if (isec) - kind = ("Section " + Twine(static_cast<uint8_t>(isec->kind()))).str(); - if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) { - kind += (" Symbol " + Twine(static_cast<uint8_t>(sym->kind()))).str(); - if (auto *d = dyn_cast<Defined>(sym)) - return getRelocHash(kind, sectionIdx.value_or(0), d->value, reloc.addend); - } - return getRelocHash(kind, sectionIdx.value_or(0), 0, reloc.addend); -} - -/// Given \p sectionIdxs, a list of section indexes, return a list of utility -/// nodes for each section index. If \p duplicateSectionIdx is provided, -/// populate it with nearly identical sections. Increment \p maxUN to be the -/// largest utility node we have used so far. -static SmallVector<std::pair<unsigned, UtilityNodes>> getUnsForCompression( - ArrayRef<const InputSection *> sections, - const DenseMap<const InputSection *, uint64_t> §ionToIdx, - ArrayRef<unsigned> sectionIdxs, - DenseMap<unsigned, SmallVector<unsigned>> *duplicateSectionIdxs, - BPFunctionNode::UtilityNodeT &maxUN) { - TimeTraceScope timeScope("Build nodes for compression"); - - SmallVector<std::pair<unsigned, SmallVector<uint64_t>>> sectionHashes; - sectionHashes.reserve(sectionIdxs.size()); - SmallVector<uint64_t> hashes; - for (unsigned sectionIdx : sectionIdxs) { - const auto *isec = sections[sectionIdx]; - constexpr unsigned windowSize = 4; - - for (size_t i = 0; i < isec->data.size(); i++) { - auto window = isec->data.drop_front(i).take_front(windowSize); - hashes.push_back(xxHash64(window)); - } - for (const auto &r : isec->relocs) { - if (r.length == 0 || r.referent.isNull() || r.offset >= isec->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 = isec->data.drop_front(i).take_front(windowSize); - hashes.push_back(xxHash64(window) + relocHash); - } - } - - llvm::sort(hashes); - hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end()); - - sectionHashes.emplace_back(sectionIdx, hashes); - hashes.clear(); - } - - DenseMap<uint64_t, unsigned> hashFrequency; - for (auto &[sectionIdx, hashes] : sectionHashes) - for (auto hash : hashes) - ++hashFrequency[hash]; - - if (duplicateSectionIdxs) { - // Merge section that are nearly identical - SmallVector<std::pair<unsigned, SmallVector<uint64_t>>> newSectionHashes; - DenseMap<uint64_t, unsigned> wholeHashToSectionIdx; - for (auto &[sectionIdx, hashes] : sectionHashes) { - uint64_t wholeHash = 0; - for (auto hash : hashes) - if (hashFrequency[hash] > 5) - wholeHash ^= hash; - auto [it, wasInserted] = - wholeHashToSectionIdx.insert(std::make_pair(wholeHash, sectionIdx)); - if (wasInserted) { - newSectionHashes.emplace_back(sectionIdx, hashes); - } else { - (*duplicateSectionIdxs)[it->getSecond()].push_back(sectionIdx); - } - } - sectionHashes = newSectionHashes; - - // Recompute hash frequencies - hashFrequency.clear(); - for (auto &[sectionIdx, hashes] : sectionHashes) - for (auto hash : hashes) - ++hashFrequency[hash]; - } - - // Filter rare and common hashes and assign each a unique utility node that - // doesn't conflict with the trace utility nodes - DenseMap<uint64_t, BPFunctionNode::UtilityNodeT> hashToUN; - for (auto &[hash, frequency] : hashFrequency) { - if (frequency <= 1 || frequency * 2 > sectionHashes.size()) - continue; - hashToUN[hash] = ++maxUN; - } - - SmallVector<std::pair<unsigned, UtilityNodes>> sectionUns; - for (auto &[sectionIdx, hashes] : sectionHashes) { - UtilityNodes uns; - for (auto &hash : hashes) { - auto it = hashToUN.find(hash); - if (it != hashToUN.end()) - uns.push_back(it->second); - } - sectionUns.emplace_back(sectionIdx, uns); - } - return sectionUns; -} - DenseMap<const InputSection *, size_t> lld::macho::runBalancedPartitioning( size_t &highestAvailablePriority, StringRef profilePath, bool forFunctionCompression, bool forDataCompression, bool compressionSortStartupFunctions, bool verbose) { - SmallVector<const InputSection *> sections; - DenseMap<const InputSection *, uint64_t> sectionToIdx; - StringMap<DenseSet<unsigned>> symbolToSectionIdxs; + SmallVector<std::unique_ptr<BPSectionBase>> sections; for (const auto *file : inputFiles) { for (auto *sec : file->sections) { for (auto &subsec : sec->subsections) { auto *isec = subsec.isec; if (!isec || isec->data.empty() || !isec->data.data()) continue; - unsigned sectionIdx = sections.size(); - sectionToIdx.try_emplace(isec, sectionIdx); - sections.push_back(isec); - for (Symbol *sym : isec->symbols) - if (auto *d = dyn_cast_or_null<Defined>(sym)) - symbolToSectionIdxs[d->getName()].insert(sectionIdx); - } - } - } - - StringMap<DenseSet<unsigned>> rootSymbolToSectionIdxs; - for (auto &entry : symbolToSectionIdxs) { - StringRef name = entry.getKey(); - auto §ionIdxs = entry.getValue(); - name = getRootSymbol(name); - rootSymbolToSectionIdxs[name].insert(sectionIdxs.begin(), - sectionIdxs.end()); - // Linkage names can be prefixed with "_" or "l_" on Mach-O. See - // Mangler::getNameWithPrefix() for details. - if (name.consume_front("_") || name.consume_front("l_")) - rootSymbolToSectionIdxs[name].insert(sectionIdxs.begin(), - sectionIdxs.end()); - } - - BPFunctionNode::UtilityNodeT maxUN = 0; - DenseMap<unsigned, UtilityNodes> startupSectionIdxUNs; - // Used to define the initial order for startup functions. - DenseMap<unsigned, size_t> sectionIdxToTimestamp; - std::unique_ptr<InstrProfReader> reader; - if (!profilePath.empty()) { - auto fs = vfs::getRealFileSystem(); - auto readerOrErr = InstrProfReader::create(profilePath, *fs); - lld::checkError(readerOrErr.takeError()); - - reader = std::move(readerOrErr.get()); - for (auto &entry : *reader) { - // Read all entries - (void)entry; - } - auto &traces = reader->getTemporalProfTraces(); - - DenseMap<unsigned, BPFunctionNode::UtilityNodeT> sectionIdxToFirstUN; - for (size_t traceIdx = 0; traceIdx < traces.size(); traceIdx++) { - uint64_t currentSize = 0, cutoffSize = 1; - size_t cutoffTimestamp = 1; - auto &trace = traces[traceIdx].FunctionNameRefs; - for (size_t timestamp = 0; timestamp < trace.size(); timestamp++) { - auto [Filename, ParsedFuncName] = getParsedIRPGOName( - reader->getSymtab().getFuncOrVarName(trace[timestamp])); - ParsedFuncName = getRootSymbol(ParsedFuncName); - - auto sectionIdxsIt = rootSymbolToSectionIdxs.find(ParsedFuncName); - if (sectionIdxsIt == rootSymbolToSectionIdxs.end()) - continue; - auto §ionIdxs = sectionIdxsIt->getValue(); - // If the same symbol is found in multiple sections, they might be - // identical, so we arbitrarily use the size from the first section. - currentSize += sections[*sectionIdxs.begin()]->getSize(); - - // Since BalancedPartitioning is sensitive to the initial order, we need - // to explicitly define it to be ordered by earliest timestamp. - for (unsigned sectionIdx : sectionIdxs) { - auto [it, wasInserted] = - sectionIdxToTimestamp.try_emplace(sectionIdx, timestamp); - if (!wasInserted) - it->getSecond() = std::min<size_t>(it->getSecond(), timestamp); - } - - if (timestamp >= cutoffTimestamp || currentSize >= cutoffSize) { - ++maxUN; - cutoffSize = 2 * currentSize; - cutoffTimestamp = 2 * cutoffTimestamp; - } - for (unsigned sectionIdx : sectionIdxs) - sectionIdxToFirstUN.try_emplace(sectionIdx, maxUN); + sections.emplace_back( + std::make_unique<BPSectionMacho>(isec, sections.size())); } - for (auto &[sectionIdx, firstUN] : sectionIdxToFirstUN) - for (auto un = firstUN; un <= maxUN; ++un) - startupSectionIdxUNs[sectionIdx].push_back(un); - ++maxUN; - sectionIdxToFirstUN.clear(); } } - SmallVector<unsigned> sectionIdxsForFunctionCompression, - sectionIdxsForDataCompression; - for (unsigned sectionIdx = 0; sectionIdx < sections.size(); sectionIdx++) { - if (startupSectionIdxUNs.count(sectionIdx)) - continue; - const auto *isec = sections[sectionIdx]; - if (isCodeSection(isec)) { - if (forFunctionCompression) - sectionIdxsForFunctionCompression.push_back(sectionIdx); - } else { - if (forDataCompression) - sectionIdxsForDataCompression.push_back(sectionIdx); - } - } + auto reorderedSections = BPSectionBase::reorderSectionsByBalancedPartitioning( + highestAvailablePriority, profilePath, forFunctionCompression, + forDataCompression, compressionSortStartupFunctions, verbose, sections); - if (compressionSortStartupFunctions) { - SmallVector<unsigned> startupIdxs; - for (auto &[sectionIdx, uns] : startupSectionIdxUNs) - startupIdxs.push_back(sectionIdx); - auto unsForStartupFunctionCompression = - getUnsForCompression(sections, sectionToIdx, startupIdxs, - /*duplicateSectionIdxs=*/nullptr, maxUN); - for (auto &[sectionIdx, compressionUns] : - unsForStartupFunctionCompression) { - auto &uns = startupSectionIdxUNs[sectionIdx]; - uns.append(compressionUns); - llvm::sort(uns); - uns.erase(std::unique(uns.begin(), uns.end()), uns.end()); + DenseMap<const InputSection *, size_t> result; + for (const auto &[sec, priority] : reorderedSections) { + if (auto *machoSection = dyn_cast<BPSectionMacho>(sec)) { + result.try_emplace( + static_cast<const InputSection *>(machoSection->getSection()), + priority); } } - - // Map a section index (order directly) to a list of duplicate section indices - // (not ordered directly). - DenseMap<unsigned, SmallVector<unsigned>> duplicateSectionIdxs; - auto unsForFunctionCompression = getUnsForCompression( - sections, sectionToIdx, sectionIdxsForFunctionCompression, - &duplicateSectionIdxs, maxUN); - auto unsForDataCompression = getUnsForCompression( - sections, sectionToIdx, sectionIdxsForDataCompression, - &duplicateSectionIdxs, maxUN); - - std::vector<BPFunctionNode> nodesForStartup, nodesForFunctionCompression, - nodesForDataCompression; - for (auto &[sectionIdx, uns] : startupSectionIdxUNs) - nodesForStartup.emplace_back(sectionIdx, uns); - for (auto &[sectionIdx, uns] : unsForFunctionCompression) - nodesForFunctionCompression.emplace_back(sectionIdx, uns); - for (auto &[sectionIdx, uns] : unsForDataCompression) - nodesForDataCompression.emplace_back(sectionIdx, uns); - - // Use the first timestamp to define the initial order for startup nodes. - llvm::sort(nodesForStartup, [§ionIdxToTimestamp](auto &L, auto &R) { - return std::make_pair(sectionIdxToTimestamp[L.Id], L.Id) < - std::make_pair(sectionIdxToTimestamp[R.Id], R.Id); - }); - // Sort compression nodes by their Id (which is the section index) because the - // input linker order tends to be not bad. - llvm::sort(nodesForFunctionCompression, - [](auto &L, auto &R) { return L.Id < R.Id; }); - llvm::sort(nodesForDataCompression, - [](auto &L, auto &R) { return L.Id < R.Id; }); - - { - TimeTraceScope timeScope("Balanced Partitioning"); - BalancedPartitioningConfig config; - BalancedPartitioning bp(config); - bp.run(nodesForStartup); - bp.run(nodesForFunctionCompression); - bp.run(nodesForDataCompression); - } - - unsigned numStartupSections = 0; - unsigned numCodeCompressionSections = 0; - unsigned numDuplicateCodeSections = 0; - unsigned numDataCompressionSections = 0; - unsigned numDuplicateDataSections = 0; - SetVector<const InputSection *> orderedSections; - // Order startup functions, - for (auto &node : nodesForStartup) { - const auto *isec = sections[node.Id]; - if (orderedSections.insert(isec)) - ++numStartupSections; - } - // then functions for compression, - for (auto &node : nodesForFunctionCompression) { - const auto *isec = sections[node.Id]; - if (orderedSections.insert(isec)) - ++numCodeCompressionSections; - - auto It = duplicateSectionIdxs.find(node.Id); - if (It == duplicateSectionIdxs.end()) - continue; - for (auto dupSecIdx : It->getSecond()) { - const auto *dupIsec = sections[dupSecIdx]; - if (orderedSections.insert(dupIsec)) - ++numDuplicateCodeSections; - } - } - // then data for compression. - for (auto &node : nodesForDataCompression) { - const auto *isec = sections[node.Id]; - if (orderedSections.insert(isec)) - ++numDataCompressionSections; - auto It = duplicateSectionIdxs.find(node.Id); - if (It == duplicateSectionIdxs.end()) - continue; - for (auto dupSecIdx : It->getSecond()) { - const auto *dupIsec = sections[dupSecIdx]; - if (orderedSections.insert(dupIsec)) - ++numDuplicateDataSections; - } - } - - if (verbose) { - unsigned numTotalOrderedSections = - numStartupSections + numCodeCompressionSections + - numDuplicateCodeSections + numDataCompressionSections + - numDuplicateDataSections; - dbgs() - << "Ordered " << numTotalOrderedSections - << " sections using balanced partitioning:\n Functions for startup: " - << numStartupSections - << "\n Functions for compression: " << numCodeCompressionSections - << "\n Duplicate functions: " << numDuplicateCodeSections - << "\n Data for compression: " << numDataCompressionSections - << "\n Duplicate data: " << numDuplicateDataSections << "\n"; - - if (!profilePath.empty()) { - // Evaluate this function order for startup - StringMap<std::pair<uint64_t, uint64_t>> symbolToPageNumbers; - const uint64_t pageSize = (1 << 14); - uint64_t currentAddress = 0; - for (const auto *isec : orderedSections) { - for (Symbol *sym : isec->symbols) { - if (auto *d = dyn_cast_or_null<Defined>(sym)) { - uint64_t startAddress = currentAddress + d->value; - uint64_t endAddress = startAddress + d->size; - uint64_t firstPage = startAddress / pageSize; - // I think the kernel might pull in a few pages when one it touched, - // so it might be more accurate to force lastPage to be aligned by - // 4? - uint64_t lastPage = endAddress / pageSize; - StringRef rootSymbol = d->getName(); - rootSymbol = getRootSymbol(rootSymbol); - symbolToPageNumbers.try_emplace(rootSymbol, firstPage, lastPage); - if (rootSymbol.consume_front("_") || rootSymbol.consume_front("l_")) - symbolToPageNumbers.try_emplace(rootSymbol, firstPage, lastPage); - } - } - - currentAddress += isec->getSize(); - } - - // The area under the curve F where F(t) is the total number of page - // faults at step t. - unsigned area = 0; - for (auto &trace : reader->getTemporalProfTraces()) { - SmallSet<uint64_t, 0> touchedPages; - for (unsigned step = 0; step < trace.FunctionNameRefs.size(); step++) { - auto traceId = trace.FunctionNameRefs[step]; - auto [Filename, ParsedFuncName] = - getParsedIRPGOName(reader->getSymtab().getFuncOrVarName(traceId)); - ParsedFuncName = getRootSymbol(ParsedFuncName); - auto it = symbolToPageNumbers.find(ParsedFuncName); - if (it != symbolToPageNumbers.end()) { - auto &[firstPage, lastPage] = it->getValue(); - for (uint64_t i = firstPage; i <= lastPage; i++) - touchedPages.insert(i); - } - area += touchedPages.size(); - } - } - dbgs() << "Total area under the page fault curve: " << (float)area - << "\n"; - } - } - - DenseMap<const InputSection *, size_t> sectionPriorities; - for (const auto *isec : orderedSections) - sectionPriorities[isec] = --highestAvailablePriority; - return sectionPriorities; + return result; } diff --git a/lld/MachO/BPSectionOrderer.h b/lld/MachO/BPSectionOrderer.h index cefd0ceb10e5..29b20c781c6b 100644 --- a/lld/MachO/BPSectionOrderer.h +++ b/lld/MachO/BPSectionOrderer.h @@ -1,4 +1,4 @@ -//===- BPSectionOrderer.h ---------------------------------------*- C++ -*-===// +//===- BPSectionOrderer.h -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -14,6 +14,10 @@ #ifndef LLD_MACHO_BPSECTION_ORDERER_H #define LLD_MACHO_BPSECTION_ORDERER_H +#include "InputSection.h" +#include "Relocations.h" +#include "Symbols.h" +#include "lld/Common/BPSectionOrdererBase.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" @@ -21,6 +25,125 @@ namespace lld::macho { class InputSection; +class BPSymbolMacho : public BPSymbol { + const Symbol *sym; + +public: + explicit BPSymbolMacho(const Symbol *s) : sym(s) {} + + llvm::StringRef getName() const override { return sym->getName(); } + + const Defined *asDefined() const { + return llvm::dyn_cast_or_null<Defined>(sym); + } + + std::optional<uint64_t> getValue() const override { + if (auto *d = asDefined()) + return d->value; + return {}; + } + + std::optional<uint64_t> getSize() const override { + if (auto *d = asDefined()) + return d->size; + return {}; + } + + const Symbol *getSymbol() const { return sym; } +}; + +class BPSectionMacho : public BPSectionBase { + const InputSection *isec; + uint64_t sectionIdx; + +public: + explicit BPSectionMacho(const InputSection *sec, uint64_t sectionIdx) + : isec(sec), sectionIdx(sectionIdx) {} + + const void *getSection() const override { return isec; } + + uint64_t getSize() const override { return isec->getSize(); } + + uint64_t getSectionIdx() const { return sectionIdx; } + + bool isCodeSection() const override { return macho::isCodeSection(isec); } + + bool hasValidData() const override { + return isec && !isec->data.empty() && isec->data.data(); + } + + SmallVector<std::unique_ptr<BPSymbol>> getSymbols() const override { + SmallVector<std::unique_ptr<BPSymbol>> symbols; + for (auto *sym : isec->symbols) + if (auto *d = llvm::dyn_cast_or_null<Defined>(sym)) + symbols.emplace_back(std::make_unique<BPSymbolMacho>(d)); + return symbols; + } + + // Linkage names can be prefixed with "_" or "l_" on Mach-O. See + // Mangler::getNameWithPrefix() for details. + std::optional<StringRef> + getResolvedLinkageName(llvm::StringRef name) const override { + if (name.consume_front("_") || name.consume_front("l_")) + return name; + return {}; + } + + void getSectionHashes(llvm::SmallVectorImpl<uint64_t> &hashes, + const llvm::DenseMap<const void *, uint64_t> + §ionToIdx) const override { + constexpr unsigned windowSize = 4; + + // Calculate content hashes + size_t dataSize = isec->data.size(); + for (size_t i = 0; i < dataSize; i++) { + auto window = isec->data.drop_front(i).take_front(windowSize); + hashes.push_back(xxHash64(window)); + } + + // Calculate relocation hashes + for (const auto &r : isec->relocs) { + if (r.length == 0 || r.referent.isNull() || r.offset >= isec->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 = isec->data.drop_front(i).take_front(windowSize); + hashes.push_back(xxHash64(window) + relocHash); + } + } + + llvm::sort(hashes); + hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end()); + } + + static bool classof(const BPSectionBase *s) { return true; } + +private: + static uint64_t + getRelocHash(const Reloc &reloc, + const llvm::DenseMap<const void *, uint64_t> §ionToIdx) { + auto *isec = reloc.getReferentInputSection(); + std::optional<uint64_t> sectionIdx; + if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end()) + sectionIdx = it->second; + std::string kind; + if (isec) + kind = ("Section " + Twine(isec->kind())).str(); + + if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) { + kind += (" Symbol " + Twine(sym->kind())).str(); + if (auto *d = llvm::dyn_cast<Defined>(sym)) { + return BPSectionBase::getRelocHash(kind, sectionIdx.value_or(0), + d->value, reloc.addend); + } + } + return BPSectionBase::getRelocHash(kind, sectionIdx.value_or(0), 0, + reloc.addend); + } +}; + /// Run Balanced Partitioning to find the optimal function and data order to /// improve startup time and compressed size. /// diff --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt index ecf6ce609e59..c778fcf7b6ff 100644 --- a/lld/MachO/CMakeLists.txt +++ b/lld/MachO/CMakeLists.txt @@ -50,7 +50,6 @@ add_lld_library(lldMachO Object Option Passes - ProfileData Support TargetParser TextAPI diff --git a/lld/MachO/ConcatOutputSection.cpp b/lld/MachO/ConcatOutputSection.cpp index e89cafe0d1e6..6a9301f84a03 100644 --- a/lld/MachO/ConcatOutputSection.cpp +++ b/lld/MachO/ConcatOutputSection.cpp @@ -145,7 +145,7 @@ bool TextOutputSection::needsThunks() const { for (Reloc &r : isec->relocs) { if (!target->hasAttr(r.type, RelocAttrBits::BRANCH)) continue; - auto *sym = r.referent.get<Symbol *>(); + auto *sym = cast<Symbol *>(r.referent); // Pre-populate the thunkMap and memoize call site counts for every // InputSection and ThunkInfo. We do this for the benefit of // estimateStubsInRangeVA(). @@ -297,7 +297,7 @@ void TextOutputSection::finalize() { backwardBranchRange < callVA ? callVA - backwardBranchRange : 0; uint64_t highVA = callVA + forwardBranchRange; // Calculate our call referent address - auto *funcSym = r.referent.get<Symbol *>(); + auto *funcSym = cast<Symbol *>(r.referent); ThunkInfo &thunkInfo = thunkMap[funcSym]; // The referent is not reachable, so we need to use a thunk ... if (funcSym->isInStubs() && callVA >= stubsInRangeVA) { diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h index 60f76d121410..d41ca5382c69 100644 --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -222,11 +222,12 @@ struct Configuration { bool callGraphProfileSort = false; llvm::StringRef printSymbolOrder; - llvm::StringRef irpgoProfileSortProfilePath; - bool compressionSortStartupFunctions = false; - bool functionOrderForCompression = false; - bool dataOrderForCompression = false; - bool verboseBpSectionOrderer = false; + llvm::StringRef irpgoProfilePath; + bool bpStartupFunctionSort = false; + bool bpCompressionSortStartupFunctions = false; + bool bpFunctionOrderForCompression = false; + bool bpDataOrderForCompression = false; + bool bpVerboseSectionOrderer = false; SectionRenameMap sectionRenameMap; SegmentRenameMap segmentRenameMap; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index c95841d3a8ad..31630ba7d69d 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1838,26 +1838,47 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS, if (const Arg *arg = args.getLastArgNoClaim(OPT_call_graph_profile_sort)) error(firstArgStr + " is incompatible with " + arg->getSpelling()); }; + if (args.hasArg(OPT_irpgo_profile_sort) || + args.hasArg(OPT_irpgo_profile_sort_eq)) + warn("--irpgo-profile-sort is deprecated. Please use " + "--bp-startup-sort=function"); + if (const Arg *arg = args.getLastArg(OPT_irpgo_profile)) + config->irpgoProfilePath = arg->getValue(); + if (const Arg *arg = args.getLastArg(OPT_irpgo_profile_sort)) { - config->irpgoProfileSortProfilePath = arg->getValue(); + config->irpgoProfilePath = arg->getValue(); + config->bpStartupFunctionSort = true; IncompatWithCGSort(arg->getSpelling()); } - config->compressionSortStartupFunctions = - args.hasFlag(OPT_compression_sort_startup_functions, - OPT_no_compression_sort_startup_functions, false); - if (config->irpgoProfileSortProfilePath.empty() && - config->compressionSortStartupFunctions) - error("--compression-sort-startup-functions must be used with " - "--irpgo-profile-sort"); - if (const Arg *arg = args.getLastArg(OPT_compression_sort)) { + config->bpCompressionSortStartupFunctions = + args.hasFlag(OPT_bp_compression_sort_startup_functions, + OPT_no_bp_compression_sort_startup_functions, false); + if (const Arg *arg = args.getLastArg(OPT_bp_startup_sort)) { + StringRef startupSortStr = arg->getValue(); + if (startupSortStr == "function") { + config->bpStartupFunctionSort = true; + } else if (startupSortStr != "none") { + error("unknown value `" + startupSortStr + "` for " + arg->getSpelling()); + } + if (startupSortStr != "none") + IncompatWithCGSort(arg->getSpelling()); + } + if (!config->bpStartupFunctionSort && + config->bpCompressionSortStartupFunctions) + error("--bp-compression-sort-startup-functions must be used with " + "--bp-startup-sort=function"); + if (config->irpgoProfilePath.empty() && config->bpStartupFunctionSort) + error("--bp-startup-sort=function must be used with " + "--irpgo-profile"); + if (const Arg *arg = args.getLastArg(OPT_bp_compression_sort)) { StringRef compressionSortStr = arg->getValue(); if (compressionSortStr == "function") { - config->functionOrderForCompression = true; + config->bpFunctionOrderForCompression = true; } else if (compressionSortStr == "data") { - config->dataOrderForCompression = true; + config->bpDataOrderForCompression = true; } else if (compressionSortStr == "both") { - config->functionOrderForCompression = true; - config->dataOrderForCompression = true; + config->bpFunctionOrderForCompression = true; + config->bpDataOrderForCompression = true; } else if (compressionSortStr != "none") { error("unknown value `" + compressionSortStr + "` for " + arg->getSpelling()); @@ -1865,7 +1886,7 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS, if (compressionSortStr != "none") IncompatWithCGSort(arg->getSpelling()); } - config->verboseBpSectionOrderer = args.hasArg(OPT_verbose_bp_section_orderer); + config->bpVerboseSectionOrderer = args.hasArg(OPT_verbose_bp_section_orderer); for (const Arg *arg : args.filtered(OPT_alias)) { config->aliasedSymbols.push_back( diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp index 308c5eaf8c31..69d023c23b3c 100644 --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -34,13 +34,14 @@ using namespace llvm::sys; using namespace lld; using namespace lld::macho; +#define OPTTABLE_STR_TABLE_CODE +#include "Options.inc" +#undef OPTTABLE_STR_TABLE_CODE + // Create prefix string literals used in Options.td -#define PREFIX(NAME, VALUE) \ - static constexpr StringLiteral NAME##_init[] = VALUE; \ - static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \ - std::size(NAME##_init) - 1); +#define OPTTABLE_PREFIXES_TABLE_CODE #include "Options.inc" -#undef PREFIX +#undef OPTTABLE_PREFIXES_TABLE_CODE // Create table mapping all options defined in Options.td static constexpr OptTable::Info optInfo[] = { @@ -65,7 +66,8 @@ static constexpr OptTable::Info optInfo[] = { #undef OPTION }; -MachOOptTable::MachOOptTable() : GenericOptTable(optInfo) {} +MachOOptTable::MachOOptTable() + : GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {} // Set color diagnostics according to --color-diagnostics={auto,always,never} // or --no-color-diagnostics flags. diff --git a/lld/MachO/EhFrame.cpp b/lld/MachO/EhFrame.cpp index 55a85f316cdd..2446b49b5098 100644 --- a/lld/MachO/EhFrame.cpp +++ b/lld/MachO/EhFrame.cpp @@ -114,7 +114,7 @@ static void createSubtraction(PointerUnion<Symbol *, InputSection *> a, auto minuend = b; if (Invert) std::swap(subtrahend, minuend); - assert(subtrahend.is<Symbol *>()); + assert(isa<Symbol *>(subtrahend)); Reloc subtrahendReloc(target->subtractorRelocType, /*pcrel=*/false, length, off, /*addend=*/0, subtrahend); Reloc minuendReloc(target->unsignedRelocType, /*pcrel=*/false, length, off, diff --git a/lld/MachO/ICF.cpp b/lld/MachO/ICF.cpp index 32dd44ab729e..75702b9c15e7 100644 --- a/lld/MachO/ICF.cpp +++ b/lld/MachO/ICF.cpp @@ -115,16 +115,16 @@ bool ICF::equalsConstant(const ConcatInputSection *ia, return false; if (ra.offset != rb.offset) return false; - if (ra.referent.is<Symbol *>() != rb.referent.is<Symbol *>()) + if (isa<Symbol *>(ra.referent) != isa<Symbol *>(rb.referent)) return false; InputSection *isecA, *isecB; uint64_t valueA = 0; uint64_t valueB = 0; - if (ra.referent.is<Symbol *>()) { - const auto *sa = ra.referent.get<Symbol *>(); - const auto *sb = rb.referent.get<Symbol *>(); + if (isa<Symbol *>(ra.referent)) { + const auto *sa = cast<Symbol *>(ra.referent); + const auto *sb = cast<Symbol *>(rb.referent); if (sa->kind() != sb->kind()) return false; // ICF runs before Undefineds are treated (and potentially converted into @@ -143,8 +143,8 @@ bool ICF::equalsConstant(const ConcatInputSection *ia, isecB = db->isec(); valueB = db->value; } else { - isecA = ra.referent.get<InputSection *>(); - isecB = rb.referent.get<InputSection *>(); + isecA = cast<InputSection *>(ra.referent); + isecB = cast<InputSection *>(rb.referent); } // Typically, we should not encounter sections marked with `keepUnique` at @@ -167,7 +167,7 @@ bool ICF::equalsConstant(const ConcatInputSection *ia, return ra.addend == rb.addend; // Else we have two literal sections. References to them are equal iff their // offsets in the output section are equal. - if (ra.referent.is<Symbol *>()) + if (isa<Symbol *>(ra.referent)) // For symbol relocs, we compare the contents at the symbol address. We // don't do `getOffset(value + addend)` because value + addend may not be // a valid offset in the literal section. @@ -195,12 +195,12 @@ bool ICF::equalsVariable(const ConcatInputSection *ia, if (ra.referent == rb.referent) return true; const ConcatInputSection *isecA, *isecB; - if (ra.referent.is<Symbol *>()) { + if (isa<Symbol *>(ra.referent)) { // Matching DylibSymbols are already filtered out by the // identical-referent check above. Non-matching DylibSymbols were filtered // out in equalsConstant(). So we can safely cast to Defined here. - const auto *da = cast<Defined>(ra.referent.get<Symbol *>()); - const auto *db = cast<Defined>(rb.referent.get<Symbol *>()); + const auto *da = cast<Defined>(cast<Symbol *>(ra.referent)); + const auto *db = cast<Defined>(cast<Symbol *>(rb.referent)); if (da->isAbsolute()) return true; isecA = dyn_cast<ConcatInputSection>(da->isec()); @@ -208,8 +208,8 @@ bool ICF::equalsVariable(const ConcatInputSection *ia, return true; // literal sections were checked in equalsConstant. isecB = cast<ConcatInputSection>(db->isec()); } else { - const auto *sa = ra.referent.get<InputSection *>(); - const auto *sb = rb.referent.get<InputSection *>(); + const auto *sa = cast<InputSection *>(ra.referent); + const auto *sb = cast<InputSection *>(rb.referent); isecA = dyn_cast<ConcatInputSection>(sa); if (!isecA) return true; diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp index c3f7c434ffca..9adfbc9d3f6f 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -1291,7 +1291,7 @@ static CIE parseCIE(const InputSection *isec, const EhReader &reader, const auto *personalityReloc = isec->getRelocAt(personalityAddrOff); if (!personalityReloc) reader.failOn(off, "Failed to locate relocation for personality symbol"); - cie.personalitySymbol = personalityReloc->referent.get<macho::Symbol *>(); + cie.personalitySymbol = cast<macho::Symbol *>(personalityReloc->referent); } return cie; } @@ -1338,12 +1338,12 @@ targetSymFromCanonicalSubtractor(const InputSection *isec, assert(target->hasAttr(minuend.type, RelocAttrBits::UNSIGNED)); // Note: pcSym may *not* be exactly at the PC; there's usually a non-zero // addend. - auto *pcSym = cast<Defined>(subtrahend.referent.get<macho::Symbol *>()); + auto *pcSym = cast<Defined>(cast<macho::Symbol *>(subtrahend.referent)); Defined *target = cast_or_null<Defined>(minuend.referent.dyn_cast<macho::Symbol *>()); if (!pcSym) { auto *targetIsec = - cast<ConcatInputSection>(minuend.referent.get<InputSection *>()); + cast<ConcatInputSection>(cast<InputSection *>(minuend.referent)); target = findSymbolAtOffset(targetIsec, minuend.addend); } if (Invert) diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp index c1b3297f321f..07e39b04cba4 100644 --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -226,13 +226,13 @@ void ConcatInputSection::writeTo(uint8_t *buf) { const bool needsFixup = config->emitChainedFixups && target->hasAttr(r.type, RelocAttrBits::UNSIGNED); if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) { - const Symbol *fromSym = r.referent.get<Symbol *>(); + const Symbol *fromSym = cast<Symbol *>(r.referent); const Reloc &minuend = relocs[++i]; uint64_t minuendVA; if (const Symbol *toSym = minuend.referent.dyn_cast<Symbol *>()) minuendVA = toSym->getVA() + minuend.addend; else { - auto *referentIsec = minuend.referent.get<InputSection *>(); + auto *referentIsec = cast<InputSection *>(minuend.referent); assert(!::shouldOmitFromOutput(referentIsec)); minuendVA = referentIsec->getVA(minuend.addend); } diff --git a/lld/MachO/MarkLive.cpp b/lld/MachO/MarkLive.cpp index c26c3aa32119..4f67f3a2d802 100644 --- a/lld/MachO/MarkLive.cpp +++ b/lld/MachO/MarkLive.cpp @@ -160,7 +160,7 @@ void MarkLiveImpl<RecordWhyLive>::markTransitively() { if (auto *s = r.referent.dyn_cast<Symbol *>()) addSym(s, entry); else - enqueue(r.referent.get<InputSection *>(), r.addend, entry); + enqueue(cast<InputSection *>(r.referent), r.addend, entry); } for (Defined *d : getInputSection(entry)->symbols) addSym(d, entry); @@ -183,7 +183,7 @@ void MarkLiveImpl<RecordWhyLive>::markTransitively() { enqueue(isec, 0, makeEntry(referentIsec, nullptr)); } } else { - auto *referentIsec = r.referent.get<InputSection *>(); + auto *referentIsec = cast<InputSection *>(r.referent); if (referentIsec->isLive(r.addend)) enqueue(isec, 0, makeEntry(referentIsec, nullptr)); } diff --git a/lld/MachO/ObjC.cpp b/lld/MachO/ObjC.cpp index ff13e8eb4b5c..272197b34e11 100644 --- a/lld/MachO/ObjC.cpp +++ b/lld/MachO/ObjC.cpp @@ -263,7 +263,7 @@ void ObjcCategoryChecker::parseCategory(const ConcatInputSection *catIsec) { if (!classReloc) return; - auto *classSym = classReloc->referent.get<Symbol *>(); + auto *classSym = cast<Symbol *>(classReloc->referent); if (auto *d = dyn_cast<Defined>(classSym)) if (!classMap.count(d)) parseClass(d); @@ -603,7 +603,7 @@ void ObjcCategoryMerger::tryEraseDefinedAtIsecOffset( if (!reloc) return; - Defined *sym = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>()); + Defined *sym = dyn_cast_or_null<Defined>(cast<Symbol *>(reloc->referent)); if (!sym) return; @@ -675,7 +675,7 @@ void ObjcCategoryMerger::parseProtocolListInfo( if (!reloc) return; - auto *ptrListSym = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>()); + auto *ptrListSym = dyn_cast_or_null<Defined>(cast<Symbol *>(reloc->referent)); assert(ptrListSym && "Protocol list reloc does not have a valid Defined"); // Theoretically protocol count can be either 32b or 64b, depending on @@ -707,7 +707,7 @@ void ObjcCategoryMerger::parseProtocolListInfo( const Reloc *reloc = ptrListSym->isec()->getRelocAt(off); assert(reloc && "No reloc found at protocol list offset"); - auto *listSym = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>()); + auto *listSym = dyn_cast_or_null<Defined>(cast<Symbol *>(reloc->referent)); assert(listSym && "Protocol list reloc does not have a valid Defined"); ptrList.allPtrs.push_back(listSym); @@ -745,7 +745,7 @@ bool ObjcCategoryMerger::parsePointerListInfo(const ConcatInputSection *isec, if (!reloc) return true; - auto *ptrListSym = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>()); + auto *ptrListSym = dyn_cast_or_null<Defined>(cast<Symbol *>(reloc->referent)); assert(ptrListSym && "Reloc does not have a valid Defined"); uint32_t thisStructSize = *reinterpret_cast<const uint32_t *>( diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td index 485e5968ff55..4b1e9e439107 100644 --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -126,19 +126,36 @@ def no_call_graph_profile_sort : Flag<["--"], "no-call-graph-profile-sort">, def print_symbol_order_eq: Joined<["--"], "print-symbol-order=">, HelpText<"Print a symbol order specified by --call-graph-profile-sort into the specified file">, Group<grp_lld>; +def irpgo_profile: Separate<["--"], "irpgo-profile">, Group<grp_lld>; +def irpgo_profile_eq: Joined<["--"], "irpgo-profile=">, + Alias<!cast<Separate>(irpgo_profile)>, MetaVarName<"<profile>">, + HelpText<"Read the IRPGO <profile> for use with -bp-startup-sort and other profile-guided optimizations">, + Group<grp_lld>; +def bp_startup_sort: Joined<["--"], "bp-startup-sort=">, + MetaVarName<"[none,function]">, + HelpText<"Order sections based on profile data to improve startup time">, + Group<grp_lld>; +def bp_compression_sort_startup_functions: Flag<["--"], "bp-compression-sort-startup-functions">, + HelpText<"Order startup functions to improve compressed size in addition to startup time">, + Group<grp_lld>; +def no_bp_compression_sort_startup_functions: Flag<["--"], "no-bp-compression-sort-startup-functions">, + HelpText<"Do not order startup function for compression">, Group<grp_lld>; +def bp_compression_sort: Joined<["--"], "bp-compression-sort=">, + MetaVarName<"[none,function,data,both]">, + HelpText<"Order sections to improve compressed size">, Group<grp_lld>; def irpgo_profile_sort: Separate<["--"], "irpgo-profile-sort">, Group<grp_lld>; def irpgo_profile_sort_eq: Joined<["--"], "irpgo-profile-sort=">, Alias<!cast<Separate>(irpgo_profile_sort)>, MetaVarName<"<profile>">, - HelpText<"Read the IRPGO profile at <profile> to order sections to improve startup time">, + HelpText<"Deprecated. Please use --irpgo-profile and --bp-startup-sort=function">, Group<grp_lld>; def compression_sort_startup_functions: Flag<["--"], "compression-sort-startup-functions">, - HelpText<"Order startup functions to improve compressed size in addition to startup time">, - Group<grp_lld>; + Alias<!cast<Flag>(bp_compression_sort_startup_functions)>, HelpText<"Deprecated. Please use --bp-compression-sort-startup-functions">, Group<grp_lld>; def no_compression_sort_startup_functions: Flag<["--"], "no-compression-sort-startup-functions">, - HelpText<"Do not order startup function for compression">, Group<grp_lld>; + Alias<!cast<Flag>(no_bp_compression_sort_startup_functions)>, HelpText<"Deprecated. Please use --no-bp-compression-sort-startup-functions">, Group<grp_lld>; def compression_sort: Joined<["--"], "compression-sort=">, MetaVarName<"[none,function,data,both]">, - HelpText<"Order sections to improve compressed size">, Group<grp_lld>; + Alias<!cast<Joined>(bp_compression_sort)>, + HelpText<"Deprecated. Please use --bp-compression-sort=">, Group<grp_lld>; def verbose_bp_section_orderer: Flag<["--"], "verbose-bp-section-orderer">, HelpText<"Print information on how many sections were ordered by balanced partitioning and a measure of the expected number of page faults">, Group<grp_lld>; diff --git a/lld/MachO/Relocations.cpp b/lld/MachO/Relocations.cpp index e8ede19d1fda..aac0e1bd3c9e 100644 --- a/lld/MachO/Relocations.cpp +++ b/lld/MachO/Relocations.cpp @@ -27,7 +27,7 @@ InputSection *Reloc::getReferentInputSection() const { return d->isec(); return nullptr; } else { - return referent.get<InputSection *>(); + return cast<InputSection *>(referent); } } @@ -38,7 +38,7 @@ StringRef Reloc::getReferentString() const { return cisec->getStringRefAtOffset(addend); } - auto *sym = dyn_cast<Defined>(referent.get<Symbol *>()); + auto *sym = dyn_cast<Defined>(cast<Symbol *>(referent)); assert(sym && "referent must be a Defined symbol"); auto *symIsec = sym->isec(); diff --git a/lld/MachO/SectionPriorities.cpp b/lld/MachO/SectionPriorities.cpp index 1e7fb5973b80..0a15112c1250 100644 --- a/lld/MachO/SectionPriorities.cpp +++ b/lld/MachO/SectionPriorities.cpp @@ -353,14 +353,16 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) { DenseMap<const InputSection *, size_t> macho::PriorityBuilder::buildInputSectionPriorities() { DenseMap<const InputSection *, size_t> sectionPriorities; - if (!config->irpgoProfileSortProfilePath.empty() || - config->functionOrderForCompression || config->dataOrderForCompression) { + if (config->bpStartupFunctionSort || config->bpFunctionOrderForCompression || + config->bpDataOrderForCompression) { TimeTraceScope timeScope("Balanced Partitioning Section Orderer"); sectionPriorities = runBalancedPartitioning( - highestAvailablePriority, config->irpgoProfileSortProfilePath, - config->functionOrderForCompression, config->dataOrderForCompression, - config->compressionSortStartupFunctions, - config->verboseBpSectionOrderer); + highestAvailablePriority, + config->bpStartupFunctionSort ? config->irpgoProfilePath : "", + config->bpFunctionOrderForCompression, + config->bpDataOrderForCompression, + config->bpCompressionSortStartupFunctions, + config->bpVerboseSectionOrderer); } else if (config->callGraphProfileSort) { // Sort sections by the profile data provided by __LLVM,__cg_profile // sections. diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp index f0a92da8777e..a61e60a944fb 100644 --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -67,10 +67,15 @@ static void transplantSymbolsAtOffset(InputSection *fromIsec, InputSection *toIsec, Defined *skip, uint64_t fromOff, uint64_t toOff) { // Ensure the symbols will still be in address order after our insertions. - auto insertIt = llvm::upper_bound(toIsec->symbols, toOff, - [](uint64_t off, const Symbol *s) { - return cast<Defined>(s)->value < off; - }); + auto symSucceedsOff = [](uint64_t off, const Symbol *s) { + return cast<Defined>(s)->value > off; + }; + assert(std::is_partitioned(toIsec->symbols.begin(), toIsec->symbols.end(), + [symSucceedsOff, toOff](const Symbol *s) { + return !symSucceedsOff(toOff, s); + }) && + "Symbols in toIsec must be partitioned by toOff."); + auto insertIt = llvm::upper_bound(toIsec->symbols, toOff, symSucceedsOff); llvm::erase_if(fromIsec->symbols, [&](Symbol *s) { auto *d = cast<Defined>(s); if (d->value != fromOff) diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp index 24844c2f3a1e..28fb8047cacd 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1990,7 +1990,7 @@ void InitOffsetsSection::setUp() { if (rel.addend != 0) error(isec->getLocation(rel.offset) + ": relocation addend is not representable in __init_offsets"); - if (rel.referent.is<InputSection *>()) + if (isa<InputSection *>(rel.referent)) error(isec->getLocation(rel.offset) + ": unexpected section relocation"); @@ -2136,12 +2136,12 @@ void ObjCMethListSection::writeRelativeOffsetForIsec( symVA = selRef->getVA(); assert(selRef->data.size() == target->wordSize && "Expected one selref per ConcatInputSection"); - } else if (reloc->referent.is<Symbol *>()) { - auto *def = dyn_cast_or_null<Defined>(reloc->referent.get<Symbol *>()); + } else if (auto *sym = dyn_cast<Symbol *>(reloc->referent)) { + auto *def = dyn_cast_or_null<Defined>(sym); assert(def && "Expected all syms in __objc_methlist to be defined"); symVA = def->getVA(); } else { - auto *isec = reloc->referent.get<InputSection *>(); + auto *isec = cast<InputSection *>(reloc->referent); symVA = isec->getVA(reloc->addend); } diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp index 7033481d6014..624464e41d77 100644 --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -390,7 +390,7 @@ void UnwindInfoSectionImpl::relocateCompactUnwind( cu.encoding = support::endian::read32le(buf + cuLayout.encodingOffset); for (const Reloc &r : d->unwindEntry()->relocs) { if (r.offset == cuLayout.personalityOffset) - cu.personality = r.referent.get<Symbol *>(); + cu.personality = cast<Symbol *>(r.referent); else if (r.offset == cuLayout.lsdaOffset) cu.lsda = r.getReferentInputSection(); } |
