summaryrefslogtreecommitdiff
path: root/lld/MachO
diff options
context:
space:
mode:
Diffstat (limited to 'lld/MachO')
-rw-r--r--lld/MachO/Arch/ARM64.cpp2
-rw-r--r--lld/MachO/BPSectionOrderer.cpp416
-rw-r--r--lld/MachO/BPSectionOrderer.h125
-rw-r--r--lld/MachO/CMakeLists.txt1
-rw-r--r--lld/MachO/ConcatOutputSection.cpp4
-rw-r--r--lld/MachO/Config.h11
-rw-r--r--lld/MachO/Driver.cpp49
-rw-r--r--lld/MachO/DriverUtils.cpp14
-rw-r--r--lld/MachO/EhFrame.cpp2
-rw-r--r--lld/MachO/ICF.cpp24
-rw-r--r--lld/MachO/InputFiles.cpp6
-rw-r--r--lld/MachO/InputSection.cpp4
-rw-r--r--lld/MachO/MarkLive.cpp4
-rw-r--r--lld/MachO/ObjC.cpp10
-rw-r--r--lld/MachO/Options.td27
-rw-r--r--lld/MachO/Relocations.cpp4
-rw-r--r--lld/MachO/SectionPriorities.cpp14
-rw-r--r--lld/MachO/SymbolTable.cpp13
-rw-r--r--lld/MachO/SyntheticSections.cpp8
-rw-r--r--lld/MachO/UnwindInfoSection.cpp2
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> &sectionToIdx) {
- 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> &sectionToIdx,
- 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 &sectionIdxs = 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 &sectionIdxs = 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, [&sectionIdxToTimestamp](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>
+ &sectionToIdx) 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> &sectionToIdx) {
+ 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();
}