Skip to content

Commit e0c7f08

Browse files
authored
[lld-macho] Refactor BPSectionOrderer with CRTP. NFC
PR #117514 refactored BPSectionOrderer to be used by the ELF port but introduced some inefficiency: * BPSectionBase/BPSymbol are wrappers around a single pointer. The numbers of sections and symbols could be huge, and the extra allocations are memory inefficient. * Reconstructing the returned DenseMap (since BPSectionBase != InputSectin) is wasteful. This patch refactors BPSectionOrderer with Curiously Recurring Template Pattern and eliminates the inefficiency. In addition, `symbolToSectionIdxs` is removed and `rootSymbolToSectionIdxs` building is moved to lld/MachO: while getting sections for symbols is cheap in Mach-O, it is awkward and inefficient in the ELF port. While here, add a file-level comment and replace some `StringMap<*>` (which copies strings) with `DenseMap<CachedHashStringRef, *>`. Pull Request: #124482
1 parent c489108 commit e0c7f08

File tree

6 files changed

+209
-258
lines changed

6 files changed

+209
-258
lines changed

lld/Common/CMakeLists.txt

-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ set_source_files_properties("${version_inc}"
2424

2525
add_lld_library(lldCommon
2626
Args.cpp
27-
BPSectionOrdererBase.cpp
2827
CommonLinkerContext.cpp
2928
DriverDispatcher.cpp
3029
DWARF.cpp
@@ -48,7 +47,6 @@ add_lld_library(lldCommon
4847
Demangle
4948
MC
5049
Option
51-
ProfileData
5250
Support
5351
Target
5452
TargetParser

lld/MachO/BPSectionOrderer.cpp

+118-16
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,141 @@
88

99
#include "BPSectionOrderer.h"
1010
#include "InputSection.h"
11+
#include "Relocations.h"
12+
#include "Symbols.h"
13+
#include "lld/Common/BPSectionOrdererBase.inc"
1114
#include "llvm/ADT/DenseMap.h"
15+
#include "llvm/ADT/StableHashing.h"
16+
#include "llvm/Support/Endian.h"
17+
#include "llvm/Support/xxhash.h"
1218

1319
#define DEBUG_TYPE "bp-section-orderer"
1420

1521
using namespace llvm;
1622
using namespace lld::macho;
1723

24+
namespace {
25+
struct BPOrdererMachO;
26+
}
27+
template <> struct lld::BPOrdererTraits<struct BPOrdererMachO> {
28+
using Section = macho::InputSection;
29+
using Symbol = macho::Symbol;
30+
};
31+
namespace {
32+
struct BPOrdererMachO : lld::BPOrderer<BPOrdererMachO> {
33+
static uint64_t getSize(const Section &sec) { return sec.getSize(); }
34+
static bool isCodeSection(const Section &sec) {
35+
return macho::isCodeSection(&sec);
36+
}
37+
static SmallVector<Symbol *, 0> getSymbols(const Section &sec) {
38+
SmallVector<Symbol *, 0> symbols;
39+
for (auto *sym : sec.symbols)
40+
if (auto *d = llvm::dyn_cast_or_null<Defined>(sym))
41+
symbols.emplace_back(d);
42+
return symbols;
43+
}
44+
45+
// Linkage names can be prefixed with "_" or "l_" on Mach-O. See
46+
// Mangler::getNameWithPrefix() for details.
47+
std::optional<StringRef> static getResolvedLinkageName(llvm::StringRef name) {
48+
if (name.consume_front("_") || name.consume_front("l_"))
49+
return name;
50+
return {};
51+
}
52+
53+
static void
54+
getSectionHashes(const Section &sec, llvm::SmallVectorImpl<uint64_t> &hashes,
55+
const llvm::DenseMap<const void *, uint64_t> &sectionToIdx) {
56+
constexpr unsigned windowSize = 4;
57+
58+
// Calculate content hashes: k-mers and the last k-1 bytes.
59+
ArrayRef<uint8_t> data = sec.data;
60+
if (data.size() >= windowSize)
61+
for (size_t i = 0; i <= data.size() - windowSize; ++i)
62+
hashes.push_back(llvm::support::endian::read32le(data.data() + i));
63+
for (uint8_t byte : data.take_back(windowSize - 1))
64+
hashes.push_back(byte);
65+
66+
// Calculate relocation hashes
67+
for (const auto &r : sec.relocs) {
68+
if (r.length == 0 || r.referent.isNull() || r.offset >= data.size())
69+
continue;
70+
71+
uint64_t relocHash = getRelocHash(r, sectionToIdx);
72+
uint32_t start = (r.offset < windowSize) ? 0 : r.offset - windowSize + 1;
73+
for (uint32_t i = start; i < r.offset + r.length; i++) {
74+
auto window = data.drop_front(i).take_front(windowSize);
75+
hashes.push_back(xxh3_64bits(window) ^ relocHash);
76+
}
77+
}
78+
79+
llvm::sort(hashes);
80+
hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end());
81+
}
82+
83+
static llvm::StringRef getSymName(const Symbol &sym) { return sym.getName(); }
84+
static uint64_t getSymValue(const Symbol &sym) {
85+
if (auto *d = dyn_cast<Defined>(&sym))
86+
return d->value;
87+
return 0;
88+
}
89+
static uint64_t getSymSize(const Symbol &sym) {
90+
if (auto *d = dyn_cast<Defined>(&sym))
91+
return d->size;
92+
return 0;
93+
}
94+
95+
private:
96+
static uint64_t
97+
getRelocHash(const Reloc &reloc,
98+
const llvm::DenseMap<const void *, uint64_t> &sectionToIdx) {
99+
auto *isec = reloc.getReferentInputSection();
100+
std::optional<uint64_t> sectionIdx;
101+
if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end())
102+
sectionIdx = it->second;
103+
uint64_t kind = -1, value = 0;
104+
if (isec)
105+
kind = uint64_t(isec->kind());
106+
107+
if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) {
108+
kind = (kind << 8) | uint8_t(sym->kind());
109+
if (auto *d = llvm::dyn_cast<Defined>(sym))
110+
value = d->value;
111+
}
112+
return llvm::stable_hash_combine(kind, sectionIdx.value_or(0), value,
113+
reloc.addend);
114+
}
115+
};
116+
} // namespace
117+
18118
DenseMap<const InputSection *, int> lld::macho::runBalancedPartitioning(
19119
StringRef profilePath, bool forFunctionCompression, bool forDataCompression,
20120
bool compressionSortStartupFunctions, bool verbose) {
21-
22-
SmallVector<std::unique_ptr<BPSectionBase>> sections;
121+
// Collect candidate sections and associated symbols.
122+
SmallVector<InputSection *> sections;
123+
DenseMap<CachedHashStringRef, DenseSet<unsigned>> rootSymbolToSectionIdxs;
23124
for (const auto *file : inputFiles) {
24125
for (auto *sec : file->sections) {
25126
for (auto &subsec : sec->subsections) {
26127
auto *isec = subsec.isec;
27-
if (!isec || isec->data.empty() || !isec->data.data())
128+
if (!isec || isec->data.empty())
28129
continue;
29-
sections.emplace_back(std::make_unique<BPSectionMacho>(isec));
130+
size_t idx = sections.size();
131+
sections.emplace_back(isec);
132+
for (auto *sym : BPOrdererMachO::getSymbols(*isec)) {
133+
auto rootName = getRootSymbol(sym->getName());
134+
rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx);
135+
if (auto linkageName =
136+
BPOrdererMachO::getResolvedLinkageName(rootName))
137+
rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert(
138+
idx);
139+
}
30140
}
31141
}
32142
}
33143

34-
auto reorderedSections = BPSectionBase::reorderSectionsByBalancedPartitioning(
35-
profilePath, forFunctionCompression, forDataCompression,
36-
compressionSortStartupFunctions, verbose, sections);
37-
38-
DenseMap<const InputSection *, int> result;
39-
for (const auto &[sec, priority] : reorderedSections) {
40-
result.try_emplace(
41-
static_cast<const InputSection *>(
42-
static_cast<const BPSectionMacho *>(sec)->getSection()),
43-
priority);
44-
}
45-
return result;
144+
return BPOrdererMachO::computeOrder(profilePath, forFunctionCompression,
145+
forDataCompression,
146+
compressionSortStartupFunctions, verbose,
147+
sections, rootSymbolToSectionIdxs);
46148
}

lld/MachO/BPSectionOrderer.h

+1-117
Original file line numberDiff line numberDiff line change
@@ -14,134 +14,18 @@
1414
#ifndef LLD_MACHO_BPSECTION_ORDERER_H
1515
#define LLD_MACHO_BPSECTION_ORDERER_H
1616

17-
#include "InputSection.h"
18-
#include "Relocations.h"
19-
#include "Symbols.h"
20-
#include "lld/Common/BPSectionOrdererBase.h"
2117
#include "llvm/ADT/DenseMap.h"
22-
#include "llvm/ADT/StableHashing.h"
2318
#include "llvm/ADT/StringRef.h"
24-
#include "llvm/Support/Endian.h"
25-
#include "llvm/Support/xxhash.h"
2619

2720
namespace lld::macho {
28-
2921
class InputSection;
3022

31-
class BPSymbolMacho : public BPSymbol {
32-
const Symbol *sym;
33-
34-
public:
35-
explicit BPSymbolMacho(const Symbol *s) : sym(s) {}
36-
37-
llvm::StringRef getName() const override { return sym->getName(); }
38-
39-
const Defined *asDefined() const {
40-
return llvm::dyn_cast_or_null<Defined>(sym);
41-
}
42-
43-
std::optional<uint64_t> getValue() const override {
44-
if (auto *d = asDefined())
45-
return d->value;
46-
return {};
47-
}
48-
49-
std::optional<uint64_t> getSize() const override {
50-
if (auto *d = asDefined())
51-
return d->size;
52-
return {};
53-
}
54-
55-
const Symbol *getSymbol() const { return sym; }
56-
};
57-
58-
class BPSectionMacho : public BPSectionBase {
59-
const InputSection *isec;
60-
61-
public:
62-
explicit BPSectionMacho(const InputSection *sec) : isec(sec) {}
63-
64-
const void *getSection() const override { return isec; }
65-
66-
uint64_t getSize() const override { return isec->getSize(); }
67-
68-
bool isCodeSection() const override { return macho::isCodeSection(isec); }
69-
70-
SmallVector<std::unique_ptr<BPSymbol>> getSymbols() const override {
71-
SmallVector<std::unique_ptr<BPSymbol>> symbols;
72-
for (auto *sym : isec->symbols)
73-
if (auto *d = llvm::dyn_cast_or_null<Defined>(sym))
74-
symbols.emplace_back(std::make_unique<BPSymbolMacho>(d));
75-
return symbols;
76-
}
77-
78-
// Linkage names can be prefixed with "_" or "l_" on Mach-O. See
79-
// Mangler::getNameWithPrefix() for details.
80-
std::optional<StringRef>
81-
getResolvedLinkageName(llvm::StringRef name) const override {
82-
if (name.consume_front("_") || name.consume_front("l_"))
83-
return name;
84-
return {};
85-
}
86-
87-
void getSectionHashes(llvm::SmallVectorImpl<uint64_t> &hashes,
88-
const llvm::DenseMap<const void *, uint64_t>
89-
&sectionToIdx) const override {
90-
constexpr unsigned windowSize = 4;
91-
92-
// Calculate content hashes: k-mers and the last k-1 bytes.
93-
ArrayRef<uint8_t> data = isec->data;
94-
if (data.size() >= windowSize)
95-
for (size_t i = 0; i <= data.size() - windowSize; ++i)
96-
hashes.push_back(llvm::support::endian::read32le(data.data() + i));
97-
for (uint8_t byte : data.take_back(windowSize - 1))
98-
hashes.push_back(byte);
99-
100-
// Calculate relocation hashes
101-
for (const auto &r : isec->relocs) {
102-
if (r.length == 0 || r.referent.isNull() || r.offset >= data.size())
103-
continue;
104-
105-
uint64_t relocHash = getRelocHash(r, sectionToIdx);
106-
uint32_t start = (r.offset < windowSize) ? 0 : r.offset - windowSize + 1;
107-
for (uint32_t i = start; i < r.offset + r.length; i++) {
108-
auto window = data.drop_front(i).take_front(windowSize);
109-
hashes.push_back(xxh3_64bits(window) ^ relocHash);
110-
}
111-
}
112-
113-
llvm::sort(hashes);
114-
hashes.erase(std::unique(hashes.begin(), hashes.end()), hashes.end());
115-
}
116-
117-
private:
118-
static uint64_t
119-
getRelocHash(const Reloc &reloc,
120-
const llvm::DenseMap<const void *, uint64_t> &sectionToIdx) {
121-
auto *isec = reloc.getReferentInputSection();
122-
std::optional<uint64_t> sectionIdx;
123-
if (auto it = sectionToIdx.find(isec); it != sectionToIdx.end())
124-
sectionIdx = it->second;
125-
uint64_t kind = -1, value = 0;
126-
if (isec)
127-
kind = uint64_t(isec->kind());
128-
129-
if (auto *sym = reloc.referent.dyn_cast<Symbol *>()) {
130-
kind = (kind << 8) | uint8_t(sym->kind());
131-
if (auto *d = llvm::dyn_cast<Defined>(sym))
132-
value = d->value;
133-
}
134-
return llvm::stable_hash_combine(kind, sectionIdx.value_or(0), value,
135-
reloc.addend);
136-
}
137-
};
138-
13923
/// Run Balanced Partitioning to find the optimal function and data order to
14024
/// improve startup time and compressed size.
14125
///
14226
/// It is important that .subsections_via_symbols is used to ensure functions
14327
/// and data are in their own sections and thus can be reordered.
144-
llvm::DenseMap<const lld::macho::InputSection *, int>
28+
llvm::DenseMap<const InputSection *, int>
14529
runBalancedPartitioning(llvm::StringRef profilePath,
14630
bool forFunctionCompression, bool forDataCompression,
14731
bool compressionSortStartupFunctions, bool verbose);

lld/MachO/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ add_lld_library(lldMachO
5050
Object
5151
Option
5252
Passes
53+
ProfileData
5354
Support
5455
TargetParser
5556
TextAPI

lld/include/lld/Common/BPSectionOrdererBase.h

-70
This file was deleted.

0 commit comments

Comments
 (0)